blob: 29bd4abaf42767fc9f89ee26679b5f1cb7d10805 [file] [log] [blame]
Andy Hungd63e79d2023-07-13 16:52:46 -07001/*
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
19namespace android {
20
21class IAfPatchPanel;
22class IAfPatchRecord;
23class IAfPatchTrack;
24class IAfPlaybackThread;
25class IAfRecordThread;
26class IAfThreadBase;
27
28class SoftwarePatch {
29public:
30 SoftwarePatch(
31 const sp<const IAfPatchPanel>& patchPanel,
32 audio_patch_handle_t patchHandle,
33 audio_io_handle_t playbackThreadHandle,
34 audio_io_handle_t recordThreadHandle)
35 : mPatchPanel(patchPanel),
36 mPatchHandle(patchHandle),
37 mPlaybackThreadHandle(playbackThreadHandle),
38 mRecordThreadHandle(recordThreadHandle) {}
39 SoftwarePatch(const SoftwarePatch&) = default;
40
41 // Must be called under AudioFlinger::mLock
42 status_t getLatencyMs_l(double* latencyMs) const;
43 audio_patch_handle_t getPatchHandle() const { return mPatchHandle; };
44 audio_io_handle_t getPlaybackThreadHandle() const { return mPlaybackThreadHandle; };
45 audio_io_handle_t getRecordThreadHandle() const { return mRecordThreadHandle; };
46
47private:
48 const sp<const IAfPatchPanel> mPatchPanel;
49 const audio_patch_handle_t mPatchHandle;
50 const audio_io_handle_t mPlaybackThreadHandle;
51 const audio_io_handle_t mRecordThreadHandle;
52};
53
54class IAfPatchPanel : public virtual RefBase {
55public:
56 static sp<IAfPatchPanel> create(AudioFlinger* audioFlinger);
57
58 // Extraction of inner Endpoint and Patch classes would require interfaces
59 // (in the Endpoint case a templated interface) but that seems
60 // excessive for now. We keep them as inner classes until extraction
61 // is needed.
62 template <typename ThreadType, typename TrackType>
63 class Endpoint final {
64 public:
65 Endpoint() = default;
66 Endpoint(const Endpoint&) = delete;
67 Endpoint& operator=(const Endpoint& other) noexcept {
68 mThread = other.mThread;
69 mCloseThread = other.mCloseThread;
70 mHandle = other.mHandle;
71 mTrack = other.mTrack;
72 return *this;
73 }
74 Endpoint(Endpoint&& other) noexcept { swap(other); }
75 Endpoint& operator=(Endpoint&& other) noexcept {
76 swap(other);
77 return *this;
78 }
79 ~Endpoint() {
80 ALOGE_IF(
81 mHandle != AUDIO_PATCH_HANDLE_NONE,
82 "A non empty Patch Endpoint leaked, handle %d", mHandle);
83 }
84
85 status_t checkTrack(TrackType* trackOrNull) const {
86 if (trackOrNull == nullptr) return NO_MEMORY;
87 return trackOrNull->initCheck();
88 }
89 audio_patch_handle_t handle() const { return mHandle; }
90 sp<ThreadType> thread() const { return mThread; }
91 sp<TrackType> track() const { return mTrack; }
92 sp<const ThreadType> const_thread() const { return mThread; }
93 sp<const TrackType> const_track() const { return mTrack; }
94
95 void closeConnections(const sp<IAfPatchPanel>& panel) {
96 if (mHandle != AUDIO_PATCH_HANDLE_NONE) {
97 panel->releaseAudioPatch(mHandle);
98 mHandle = AUDIO_PATCH_HANDLE_NONE;
99 }
100 if (mThread != nullptr) {
101 if (mTrack != nullptr) {
102 mThread->deletePatchTrack(mTrack);
103 }
104 if (mCloseThread) {
105 panel->closeThreadInternal_l(mThread);
106 }
107 }
108 }
109 audio_patch_handle_t* handlePtr() { return &mHandle; }
110 void setThread(const sp<ThreadType>& thread, bool closeThread = true) {
111 mThread = thread;
112 mCloseThread = closeThread;
113 }
114 template <typename T>
115 void setTrackAndPeer(const sp<TrackType>& track, const sp<T>& peer, bool holdReference) {
116 mTrack = track;
117 mThread->addPatchTrack(mTrack);
118 mTrack->setPeerProxy(peer, holdReference);
119 mClearPeerProxy = holdReference;
120 }
121 void clearTrackPeer() {
122 if (mClearPeerProxy && mTrack) mTrack->clearPeerProxy();
123 }
124 void stopTrack() {
125 if (mTrack) mTrack->stop();
126 }
127
128 void swap(Endpoint& other) noexcept {
129 using std::swap;
130 swap(mThread, other.mThread);
131 swap(mCloseThread, other.mCloseThread);
132 swap(mClearPeerProxy, other.mClearPeerProxy);
133 swap(mHandle, other.mHandle);
134 swap(mTrack, other.mTrack);
135 }
136
137 friend void swap(Endpoint& a, Endpoint& b) noexcept { a.swap(b); }
138
139 private:
140 sp<ThreadType> mThread;
141 bool mCloseThread = true;
142 bool mClearPeerProxy = true;
143 audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
144 sp<TrackType> mTrack;
145 };
146
147 class Patch final {
148 public:
149 Patch(const struct audio_patch& patch, bool endpointPatch)
150 : mAudioPatch(patch), mIsEndpointPatch(endpointPatch) {}
151 Patch() = default;
152 ~Patch();
153 Patch(const Patch& other) noexcept {
154 mAudioPatch = other.mAudioPatch;
155 mHalHandle = other.mHalHandle;
156 mPlayback = other.mPlayback;
157 mRecord = other.mRecord;
158 mThread = other.mThread;
159 mIsEndpointPatch = other.mIsEndpointPatch;
160 }
161 Patch(Patch&& other) noexcept { swap(other); }
162 Patch& operator=(Patch&& other) noexcept {
163 swap(other);
164 return *this;
165 }
166
167 void swap(Patch& other) noexcept {
168 using std::swap;
169 swap(mAudioPatch, other.mAudioPatch);
170 swap(mHalHandle, other.mHalHandle);
171 swap(mPlayback, other.mPlayback);
172 swap(mRecord, other.mRecord);
173 swap(mThread, other.mThread);
174 swap(mIsEndpointPatch, other.mIsEndpointPatch);
175 }
176
177 friend void swap(Patch& a, Patch& b) noexcept { a.swap(b); }
178
179 status_t createConnections(const sp<IAfPatchPanel>& panel);
180 void clearConnections(const sp<IAfPatchPanel>& panel);
181 bool isSoftware() const {
182 return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
183 mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE;
184 }
185
186 void setThread(const sp<IAfThreadBase>& thread) { mThread = thread; }
187 wp<IAfThreadBase> thread() const { return mThread; }
188
189 // returns the latency of the patch (from record to playback).
190 status_t getLatencyMs(double* latencyMs) const;
191
192 String8 dump(audio_patch_handle_t myHandle) const;
193
194 // Note that audio_patch::id is only unique within a HAL module
195 struct audio_patch mAudioPatch;
196 // handle for audio HAL patch handle present only when the audio HAL version is >= 3.0
197 audio_patch_handle_t mHalHandle = AUDIO_PATCH_HANDLE_NONE;
198 // below members are used by a software audio patch connecting a source device from a
199 // given audio HW module to a sink device on an other audio HW module.
200 // the objects are created by createConnections() and released by clearConnections()
201 // playback thread is created if no existing playback thread can be used
202 // connects playback thread output to sink device
203 Endpoint<IAfPlaybackThread, IAfPatchTrack> mPlayback;
204 // connects source device to record thread input
205 Endpoint<IAfRecordThread, IAfPatchRecord> mRecord;
206
207 wp<IAfThreadBase> mThread;
208 bool mIsEndpointPatch;
209 };
210
211 /* List connected audio ports and their attributes */
212 virtual status_t listAudioPorts(unsigned int* num_ports, struct audio_port* ports) = 0;
213
214 /* Get supported attributes for a given audio port */
215 virtual status_t getAudioPort(struct audio_port_v7* port) = 0;
216
217 /* Create a patch between several source and sink ports */
218 virtual status_t createAudioPatch(
219 const struct audio_patch* patch,
220 audio_patch_handle_t* handle,
221 bool endpointPatch = false) = 0;
222
223 /* Release a patch */
224 virtual status_t releaseAudioPatch(audio_patch_handle_t handle) = 0;
225
226 /* List connected audio devices and they attributes */
227 virtual status_t listAudioPatches(unsigned int* num_patches, struct audio_patch* patches) = 0;
228
229 // Retrieves all currently estrablished software patches for a stream
230 // opened on an intermediate module.
231 virtual status_t getDownstreamSoftwarePatches(
232 audio_io_handle_t stream, std::vector<SoftwarePatch>* patches) const = 0;
233
234 // Notifies patch panel about all opened and closed streams.
235 virtual void notifyStreamOpened(
236 AudioHwDevice* audioHwDevice, audio_io_handle_t stream, struct audio_patch* patch) = 0;
237
238 virtual void notifyStreamClosed(audio_io_handle_t stream) = 0;
239
240 virtual void dump(int fd) const = 0;
241
242 // Must be called under AudioFlinger::mLock
243
244 virtual const std::map<audio_patch_handle_t, Patch>& patches_l() const = 0;
245
246 virtual status_t getLatencyMs_l(audio_patch_handle_t patchHandle, double* latencyMs) const = 0;
247
248 virtual void closeThreadInternal_l(const sp<IAfThreadBase>& thread) const = 0;
249};
250
251} // namespace android