xref: /aosp_15_r20/frameworks/av/services/audioflinger/IAfPatchPanel.h (revision ec779b8e0859a360c3d303172224686826e6e0e1)
1 /*
2  * Copyright (C) 2023 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 // The following includes are required because we have class definitions below
20 // for EndPoint and Patch, which precludes using a forward declaration only.
21 #include "IAfThread.h"  // IAfThreadBase IAfMmapThread IAfPlaybackThread IAfRecordThread
22 #include "IAfTrack.h"   // IAfPatchRecord IAfPatchTrack
23 
24 #include <datapath/AudioHwDevice.h>
25 #include <media/DeviceDescriptorBase.h>
26 #include <utils/Log.h>      // ALOG used in this file
27 #include <utils/RefBase.h>  // avoid transitive dependency
28 #include <utils/Thread.h>
29 
30 namespace android {
31 
32 class IAfPatchPanel;
33 class PatchCommandThread;
34 
35 class SoftwarePatch {
36 public:
SoftwarePatch(const sp<const IAfPatchPanel> & patchPanel,audio_patch_handle_t patchHandle,audio_io_handle_t playbackThreadHandle,audio_io_handle_t recordThreadHandle)37     SoftwarePatch(
38             const sp<const IAfPatchPanel>& patchPanel,
39             audio_patch_handle_t patchHandle,
40             audio_io_handle_t playbackThreadHandle,
41             audio_io_handle_t recordThreadHandle)
42         : mPatchPanel(patchPanel),
43           mPatchHandle(patchHandle),
44           mPlaybackThreadHandle(playbackThreadHandle),
45           mRecordThreadHandle(recordThreadHandle) {}
46     SoftwarePatch(const SoftwarePatch&) = default;
47 
48     status_t getLatencyMs_l(double* latencyMs) const REQUIRES(audio_utils::AudioFlinger_Mutex);
getPatchHandle()49     audio_patch_handle_t getPatchHandle() const { return mPatchHandle; };
getPlaybackThreadHandle()50     audio_io_handle_t getPlaybackThreadHandle() const { return mPlaybackThreadHandle; };
getRecordThreadHandle()51     audio_io_handle_t getRecordThreadHandle() const { return mRecordThreadHandle; };
52 
53 private:
54     const sp<const IAfPatchPanel> mPatchPanel;
55     const audio_patch_handle_t mPatchHandle;
56     const audio_io_handle_t mPlaybackThreadHandle;
57     const audio_io_handle_t mRecordThreadHandle;
58 };
59 
60 class IAfPatchPanelCallback : public virtual RefBase {
61 public:
62     virtual void closeThreadInternal_l(const sp<IAfPlaybackThread>& thread) REQUIRES(mutex()) = 0;
63     virtual void closeThreadInternal_l(const sp<IAfRecordThread>& thread) REQUIRES(mutex()) = 0;
64     virtual IAfPlaybackThread* primaryPlaybackThread_l() const REQUIRES(mutex()) = 0;
65     virtual IAfPlaybackThread* checkPlaybackThread_l(audio_io_handle_t output) const
66             REQUIRES(mutex()) = 0;
67     virtual IAfRecordThread* checkRecordThread_l(audio_io_handle_t input) const
68             REQUIRES(mutex()) = 0;
69     virtual IAfMmapThread* checkMmapThread_l(audio_io_handle_t io) const REQUIRES(mutex()) = 0;
70     virtual sp<IAfThreadBase> openInput_l(audio_module_handle_t module,
71             audio_io_handle_t* input,
72             audio_config_t* config,
73             audio_devices_t device,
74             const char* address,
75             audio_source_t source,
76             audio_input_flags_t flags,
77             audio_devices_t outputDevice,
78             const String8& outputDeviceAddress) REQUIRES(mutex()) = 0;
79     virtual sp<IAfThreadBase> openOutput_l(audio_module_handle_t module,
80             audio_io_handle_t* output,
81             audio_config_t* halConfig,
82             audio_config_base_t* mixerConfig,
83             audio_devices_t deviceType,
84             const String8& address,
85             audio_output_flags_t* flags,
86             audio_attributes_t attributes) REQUIRES(mutex()) = 0;
87     virtual audio_utils::mutex& mutex() const
88             RETURN_CAPABILITY(audio_utils::AudioFlinger_Mutex) = 0;
89     virtual const DefaultKeyedVector<audio_module_handle_t, AudioHwDevice*>&
90             getAudioHwDevs_l() const REQUIRES(mutex()) = 0;
91     virtual audio_unique_id_t nextUniqueId(audio_unique_id_use_t use) = 0;
92     virtual const sp<PatchCommandThread>& getPatchCommandThread() = 0;
93     virtual void updateDownStreamPatches_l(
94             const struct audio_patch* patch, const std::set<audio_io_handle_t>& streams)
95             REQUIRES(mutex()) = 0;
96     virtual void updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices)
97             REQUIRES(mutex()) = 0;
98 };
99 
100 class IAfPatchPanel : public virtual RefBase {
101 public:
102     static sp<IAfPatchPanel> create(const sp<IAfPatchPanelCallback>& afPatchPanelCallback);
103 
104     // Extraction of inner Endpoint and Patch classes would require interfaces
105     // (in the Endpoint case a templated interface) but that seems
106     // excessive for now.  We keep them as inner classes until extraction
107     // is needed.
108     template <typename ThreadType, typename TrackType>
109     class Endpoint final {
110     public:
111         Endpoint() = default;
112         Endpoint(const Endpoint&) = delete;
113         Endpoint& operator=(const Endpoint& other) noexcept {
114             mThread = other.mThread;
115             mCloseThread = other.mCloseThread;
116             mHandle = other.mHandle;
117             mTrack = other.mTrack;
118             return *this;
119         }
Endpoint(Endpoint && other)120         Endpoint(Endpoint&& other) noexcept { swap(other); }
121         Endpoint& operator=(Endpoint&& other) noexcept {
122             swap(other);
123             return *this;
124         }
~Endpoint()125         ~Endpoint() {
126             ALOGE_IF(
127                     mHandle != AUDIO_PATCH_HANDLE_NONE,
128                     "A non empty Patch Endpoint leaked, handle %d", mHandle);
129         }
130 
checkTrack(TrackType * trackOrNull)131         status_t checkTrack(TrackType* trackOrNull) const {
132             if (trackOrNull == nullptr) return NO_MEMORY;
133             return trackOrNull->initCheck();
134         }
handle()135         audio_patch_handle_t handle() const { return mHandle; }
thread()136         sp<ThreadType> thread() const { return mThread; }
track()137         sp<TrackType> track() const { return mTrack; }
const_thread()138         sp<const ThreadType> const_thread() const { return mThread; }
const_track()139         sp<const TrackType> const_track() const { return mTrack; }
140 
closeConnections_l(const sp<IAfPatchPanel> & panel)141         void closeConnections_l(const sp<IAfPatchPanel>& panel)
142                 REQUIRES(audio_utils::AudioFlinger_Mutex)
143                 NO_THREAD_SAFETY_ANALYSIS // this is broken in clang
144         {
145             if (mHandle != AUDIO_PATCH_HANDLE_NONE) {
146                 panel->releaseAudioPatch_l(mHandle);
147                 mHandle = AUDIO_PATCH_HANDLE_NONE;
148             }
149             if (mThread != nullptr) {
150                 if (mTrack != nullptr) {
151                     mThread->deletePatchTrack(mTrack);
152                 }
153                 if (mCloseThread) {
154                     panel->closeThreadInternal_l(mThread);
155                 }
156             }
157         }
handlePtr()158         audio_patch_handle_t* handlePtr() { return &mHandle; }
159         void setThread(const sp<ThreadType>& thread, bool closeThread = true) {
160             mThread = thread;
161             mCloseThread = closeThread;
162         }
163         template <typename T>
setTrackAndPeer(const sp<TrackType> & track,const sp<T> & peer,bool holdReference)164         void setTrackAndPeer(const sp<TrackType>& track, const sp<T>& peer, bool holdReference) {
165             mTrack = track;
166             mThread->addPatchTrack(mTrack);
167             mTrack->setPeerProxy(peer, holdReference);
168             mClearPeerProxy = holdReference;
169         }
clearTrackPeer()170         void clearTrackPeer() {
171             if (mClearPeerProxy && mTrack) mTrack->clearPeerProxy();
172         }
stopTrack()173         void stopTrack() {
174             if (mTrack) mTrack->stop();
175         }
176 
swap(Endpoint & other)177         void swap(Endpoint& other) noexcept {
178             using std::swap;
179             swap(mThread, other.mThread);
180             swap(mCloseThread, other.mCloseThread);
181             swap(mClearPeerProxy, other.mClearPeerProxy);
182             swap(mHandle, other.mHandle);
183             swap(mTrack, other.mTrack);
184         }
185 
swap(Endpoint & a,Endpoint & b)186         friend void swap(Endpoint& a, Endpoint& b) noexcept { a.swap(b); }
187 
188     private:
189         sp<ThreadType> mThread;
190         bool mCloseThread = true;
191         bool mClearPeerProxy = true;
192         audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
193         sp<TrackType> mTrack;
194     };
195 
196     class Patch final {
197     public:
Patch(const struct audio_patch & patch,bool endpointPatch)198         Patch(const struct audio_patch& patch, bool endpointPatch)
199             : mAudioPatch(patch), mIsEndpointPatch(endpointPatch) {}
200         Patch() = default;
201         ~Patch();
Patch(const Patch & other)202         Patch(const Patch& other) noexcept {
203             mAudioPatch = other.mAudioPatch;
204             mHalHandle = other.mHalHandle;
205             mPlayback = other.mPlayback;
206             mRecord = other.mRecord;
207             mThread = other.mThread;
208             mIsEndpointPatch = other.mIsEndpointPatch;
209         }
Patch(Patch && other)210         Patch(Patch&& other) noexcept { swap(other); }
211         Patch& operator=(Patch&& other) noexcept {
212             swap(other);
213             return *this;
214         }
215 
swap(Patch & other)216         void swap(Patch& other) noexcept {
217             using std::swap;
218             swap(mAudioPatch, other.mAudioPatch);
219             swap(mHalHandle, other.mHalHandle);
220             swap(mPlayback, other.mPlayback);
221             swap(mRecord, other.mRecord);
222             swap(mThread, other.mThread);
223             swap(mIsEndpointPatch, other.mIsEndpointPatch);
224         }
225 
swap(Patch & a,Patch & b)226         friend void swap(Patch& a, Patch& b) noexcept { a.swap(b); }
227 
228         status_t createConnections_l(const sp<IAfPatchPanel>& panel)
229                 REQUIRES(audio_utils::AudioFlinger_Mutex);
230         void clearConnections_l(const sp<IAfPatchPanel>& panel)
231                 REQUIRES(audio_utils::AudioFlinger_Mutex);
isSoftware()232         bool isSoftware() const {
233             return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
234                    mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE;
235         }
236 
setThread(const sp<IAfThreadBase> & thread)237         void setThread(const sp<IAfThreadBase>& thread) { mThread = thread; }
thread()238         wp<IAfThreadBase> thread() const { return mThread; }
239 
240         // returns the latency of the patch (from record to playback).
241         status_t getLatencyMs(double* latencyMs) const;
242 
243         String8 dump(audio_patch_handle_t myHandle) const;
244 
245         // Note that audio_patch::id is only unique within a HAL module
246         struct audio_patch mAudioPatch;
247         // handle for audio HAL patch handle present only when the audio HAL version is >= 3.0
248         audio_patch_handle_t mHalHandle = AUDIO_PATCH_HANDLE_NONE;
249         // below members are used by a software audio patch connecting a source device from a
250         // given audio HW module to a sink device on an other audio HW module.
251         // the objects are created by createConnections() and released by clearConnections()
252         // playback thread is created if no existing playback thread can be used
253         // connects playback thread output to sink device
254         Endpoint<IAfPlaybackThread, IAfPatchTrack> mPlayback;
255         // connects source device to record thread input
256         Endpoint<IAfRecordThread, IAfPatchRecord> mRecord;
257 
258         wp<IAfThreadBase> mThread;
259         bool mIsEndpointPatch;
260     };
261 
262     /* List connected audio ports and their attributes */
263     virtual status_t listAudioPorts_l(unsigned int* num_ports, struct audio_port* ports)
264             REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
265 
266     /* Get supported attributes for a given audio port */
267     virtual status_t getAudioPort_l(struct audio_port_v7* port)
268             REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
269 
270     /* Create a patch between several source and sink ports */
271     virtual status_t createAudioPatch_l(
272             const struct audio_patch* patch,
273             audio_patch_handle_t* handle,
274             bool endpointPatch = false)
275             REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
276 
277     /* Release a patch */
278     virtual status_t releaseAudioPatch_l(audio_patch_handle_t handle)
279             REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
280 
281     /* List connected audio devices and they attributes */
282     virtual status_t listAudioPatches_l(unsigned int* num_patches, struct audio_patch* patches)
283             REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
284 
285     // Retrieves all currently estrablished software patches for a stream
286     // opened on an intermediate module.
287     virtual status_t getDownstreamSoftwarePatches(
288             audio_io_handle_t stream, std::vector<SoftwarePatch>* patches) const = 0;
289 
290     // Notifies patch panel about all opened and closed streams.
291     virtual void notifyStreamOpened(
292             AudioHwDevice* audioHwDevice, audio_io_handle_t stream, struct audio_patch* patch) = 0;
293 
294     virtual void notifyStreamClosed(audio_io_handle_t stream) = 0;
295 
296     virtual void dump(int fd) const = 0;
297 
298     virtual const std::map<audio_patch_handle_t, Patch>& patches_l() const
299             REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
300 
301     virtual status_t getLatencyMs_l(audio_patch_handle_t patchHandle, double* latencyMs) const
302             REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
303 
304     virtual void closeThreadInternal_l(const sp<IAfThreadBase>& thread) const
305             REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
306 
307     /**
308      * Get the attributes of the mix port when connecting to the given device port.
309      */
310     virtual status_t getAudioMixPort_l(
311             const struct audio_port_v7* devicePort,
312             struct audio_port_v7* mixPort) REQUIRES(audio_utils::AudioFlinger_Mutex) = 0;
313 };
314 
315 }  // namespace android
316