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