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