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