blob: 4e0d243f7e7ef79ef829d2838cc309222659132d [file] [log] [blame]
Eric Laurent1c333e22014-05-20 10:48:17 -07001/*
2**
3** Copyright 2014, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#ifndef INCLUDING_FROM_AUDIOFLINGER_H
19 #error This header file should only be included from AudioFlinger.h
20#endif
21
Mikhail Naganovadca70f2018-07-09 12:49:25 -070022
Mikhail Naganovdea53042018-04-26 13:10:21 -070023// PatchPanel is concealed within AudioFlinger, their lifetimes are the same.
24class PatchPanel {
Eric Laurent1c333e22014-05-20 10:48:17 -070025public:
Mikhail Naganovadca70f2018-07-09 12:49:25 -070026 class SoftwarePatch {
27 public:
28 SoftwarePatch(const PatchPanel &patchPanel, audio_patch_handle_t patchHandle,
29 audio_io_handle_t playbackThreadHandle, audio_io_handle_t recordThreadHandle)
30 : mPatchPanel(patchPanel), mPatchHandle(patchHandle),
31 mPlaybackThreadHandle(playbackThreadHandle),
32 mRecordThreadHandle(recordThreadHandle) {}
33 SoftwarePatch(const SoftwarePatch&) = default;
34 SoftwarePatch& operator=(const SoftwarePatch&) = default;
35
36 // Must be called under AudioFlinger::mLock
37 status_t getLatencyMs_l(double *latencyMs) const;
Andy Hung2dbffc22018-08-08 18:50:41 -070038 audio_patch_handle_t getPatchHandle() const { return mPatchHandle; };
Mikhail Naganovadca70f2018-07-09 12:49:25 -070039 audio_io_handle_t getPlaybackThreadHandle() const { return mPlaybackThreadHandle; };
40 audio_io_handle_t getRecordThreadHandle() const { return mRecordThreadHandle; };
41 private:
42 const PatchPanel &mPatchPanel;
43 const audio_patch_handle_t mPatchHandle;
44 const audio_io_handle_t mPlaybackThreadHandle;
45 const audio_io_handle_t mRecordThreadHandle;
46 };
47
Mikhail Naganovdea53042018-04-26 13:10:21 -070048 explicit PatchPanel(AudioFlinger* audioFlinger) : mAudioFlinger(*audioFlinger) {}
Eric Laurent1c333e22014-05-20 10:48:17 -070049
50 /* List connected audio ports and their attributes */
51 status_t listAudioPorts(unsigned int *num_ports,
52 struct audio_port *ports);
53
54 /* Get supported attributes for a given audio port */
55 status_t getAudioPort(struct audio_port *port);
56
57 /* Create a patch between several source and sink ports */
58 status_t createAudioPatch(const struct audio_patch *patch,
59 audio_patch_handle_t *handle);
60
61 /* Release a patch */
62 status_t releaseAudioPatch(audio_patch_handle_t handle);
63
64 /* List connected audio devices and they attributes */
65 status_t listAudioPatches(unsigned int *num_patches,
66 struct audio_patch *patches);
67
Mikhail Naganovadca70f2018-07-09 12:49:25 -070068 // Retrieves all currently estrablished software patches for a stream
69 // opened on an intermediate module.
70 status_t getDownstreamSoftwarePatches(audio_io_handle_t stream,
71 std::vector<SoftwarePatch> *patches) const;
72
73 // Notifies patch panel about all opened and closed streams.
74 void notifyStreamOpened(AudioHwDevice *audioHwDevice, audio_io_handle_t stream);
75 void notifyStreamClosed(audio_io_handle_t stream);
76
77 void dump(int fd) const;
Mikhail Naganov201369b2018-05-16 16:52:32 -070078
Mikhail Naganov444ecc32018-05-01 17:40:05 -070079 template<typename ThreadType, typename TrackType>
Eric Laurent9b2064c2019-11-22 17:25:04 -080080 class Endpoint final {
Mikhail Naganov444ecc32018-05-01 17:40:05 -070081 public:
Mikhail Naganov9dfa2642018-05-10 10:09:19 -070082 Endpoint() = default;
Mikhail Naganovfa97d9b2019-02-05 14:08:21 -080083 Endpoint(const Endpoint&) = delete;
Eric Laurent9b2064c2019-11-22 17:25:04 -080084 Endpoint& operator=(const Endpoint& other) noexcept {
85 mThread = other.mThread;
86 mCloseThread = other.mCloseThread;
87 mHandle = other.mHandle;
88 mTrack = other.mTrack;
89 return *this;
90 }
Mikhail Naganovfa97d9b2019-02-05 14:08:21 -080091 Endpoint(Endpoint&& other) noexcept { swap(other); }
92 Endpoint& operator=(Endpoint&& other) noexcept {
93 swap(other);
94 return *this;
95 }
96 ~Endpoint() {
Mikhail Naganov9dfa2642018-05-10 10:09:19 -070097 ALOGE_IF(mHandle != AUDIO_PATCH_HANDLE_NONE,
98 "A non empty Patch Endpoint leaked, handle %d", mHandle);
Mikhail Naganov9dfa2642018-05-10 10:09:19 -070099 }
100
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700101 status_t checkTrack(TrackType *trackOrNull) const {
102 if (trackOrNull == nullptr) return NO_MEMORY;
103 return trackOrNull->initCheck();
104 }
105 audio_patch_handle_t handle() const { return mHandle; }
Eric Laurent9b2064c2019-11-22 17:25:04 -0800106 sp<ThreadType> thread() const { return mThread; }
107 sp<TrackType> track() const { return mTrack; }
Mikhail Naganovadca70f2018-07-09 12:49:25 -0700108 sp<const ThreadType> const_thread() const { return mThread; }
Andy Hungc3ab7732018-06-01 13:46:29 -0700109 sp<const TrackType> const_track() const { return mTrack; }
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700110
111 void closeConnections(PatchPanel *panel) {
112 if (mHandle != AUDIO_PATCH_HANDLE_NONE) {
113 panel->releaseAudioPatch(mHandle);
114 mHandle = AUDIO_PATCH_HANDLE_NONE;
115 }
116 if (mThread != 0) {
117 if (mTrack != 0) {
118 mThread->deletePatchTrack(mTrack);
119 }
120 if (mCloseThread) {
121 panel->mAudioFlinger.closeThreadInternal_l(mThread);
122 }
123 }
124 }
125 audio_patch_handle_t* handlePtr() { return &mHandle; }
126 void setThread(const sp<ThreadType>& thread, bool closeThread = true) {
127 mThread = thread;
128 mCloseThread = closeThread;
129 }
Andy Hungabfab202019-03-07 19:45:54 -0800130 template <typename T>
131 void setTrackAndPeer(const sp<TrackType>& track, const sp<T> &peer) {
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700132 mTrack = track;
133 mThread->addPatchTrack(mTrack);
Andy Hungabfab202019-03-07 19:45:54 -0800134 mTrack->setPeerProxy(peer, true /* holdReference */);
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700135 }
Mikhail Naganovd3f301c2019-03-11 08:58:03 -0700136 void clearTrackPeer() { if (mTrack) mTrack->clearPeerProxy(); }
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700137 void stopTrack() { if (mTrack) mTrack->stop(); }
138
Mikhail Naganovfa97d9b2019-02-05 14:08:21 -0800139 void swap(Endpoint &other) noexcept {
140 using std::swap;
141 swap(mThread, other.mThread);
142 swap(mCloseThread, other.mCloseThread);
143 swap(mHandle, other.mHandle);
144 swap(mTrack, other.mTrack);
145 }
Mikhail Naganov9dfa2642018-05-10 10:09:19 -0700146
Mikhail Naganovfa97d9b2019-02-05 14:08:21 -0800147 friend void swap(Endpoint &a, Endpoint &b) noexcept {
148 a.swap(b);
149 }
150
151 private:
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700152 sp<ThreadType> mThread;
153 bool mCloseThread = true;
154 audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
155 sp<TrackType> mTrack;
156 };
157
Eric Laurent9b2064c2019-11-22 17:25:04 -0800158 class Patch final {
Eric Laurent1c333e22014-05-20 10:48:17 -0700159 public:
Mikhail Naganovdea53042018-04-26 13:10:21 -0700160 explicit Patch(const struct audio_patch &patch) : mAudioPatch(patch) {}
Eric Laurent9b2064c2019-11-22 17:25:04 -0800161 Patch() = default;
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700162 ~Patch();
Eric Laurent9b2064c2019-11-22 17:25:04 -0800163 Patch(const Patch& other) noexcept {
164 mAudioPatch = other.mAudioPatch;
165 mHalHandle = other.mHalHandle;
166 mPlayback = other.mPlayback;
167 mRecord = other.mRecord;
168 mThread = other.mThread;
169 }
170 Patch(Patch&& other) noexcept { swap(other); }
171 Patch& operator=(Patch&& other) noexcept {
172 swap(other);
173 return *this;
174 }
175
176 void swap(Patch &other) noexcept {
177 using std::swap;
178 swap(mAudioPatch, other.mAudioPatch);
179 swap(mHalHandle, other.mHalHandle);
180 swap(mPlayback, other.mPlayback);
181 swap(mRecord, other.mRecord);
182 swap(mThread, other.mThread);
183 }
184
185 friend void swap(Patch &a, Patch &b) noexcept {
186 a.swap(b);
187 }
Eric Laurent1c333e22014-05-20 10:48:17 -0700188
Mikhail Naganovdea53042018-04-26 13:10:21 -0700189 status_t createConnections(PatchPanel *panel);
190 void clearConnections(PatchPanel *panel);
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700191 bool isSoftware() const {
192 return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
193 mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; }
Mikhail Naganovdea53042018-04-26 13:10:21 -0700194
Eric Laurent9b2064c2019-11-22 17:25:04 -0800195 void setThread(sp<ThreadBase> thread) { mThread = thread; }
196 wp<ThreadBase> thread() const { return mThread; }
197
Andy Hungc3ab7732018-06-01 13:46:29 -0700198 // returns the latency of the patch (from record to playback).
199 status_t getLatencyMs(double *latencyMs) const;
200
Mikhail Naganovadca70f2018-07-09 12:49:25 -0700201 String8 dump(audio_patch_handle_t myHandle) const;
Mikhail Naganov201369b2018-05-16 16:52:32 -0700202
Mikhail Naganovdea53042018-04-26 13:10:21 -0700203 // Note that audio_patch::id is only unique within a HAL module
Eric Laurent83b88082014-06-20 18:31:16 -0700204 struct audio_patch mAudioPatch;
Eric Laurentb997d3a2016-06-07 18:23:45 -0700205 // handle for audio HAL patch handle present only when the audio HAL version is >= 3.0
Mikhail Naganovdea53042018-04-26 13:10:21 -0700206 audio_patch_handle_t mHalHandle = AUDIO_PATCH_HANDLE_NONE;
Eric Laurentb997d3a2016-06-07 18:23:45 -0700207 // below members are used by a software audio patch connecting a source device from a
208 // given audio HW module to a sink device on an other audio HW module.
Mikhail Naganovdea53042018-04-26 13:10:21 -0700209 // the objects are created by createConnections() and released by clearConnections()
210 // playback thread is created if no existing playback thread can be used
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700211 // connects playback thread output to sink device
212 Endpoint<PlaybackThread, PlaybackThread::PatchTrack> mPlayback;
213 // connects source device to record thread input
214 Endpoint<RecordThread, RecordThread::PatchRecord> mRecord;
Eric Laurent9b2064c2019-11-22 17:25:04 -0800215
216 wp<ThreadBase> mThread;
Eric Laurent1c333e22014-05-20 10:48:17 -0700217 };
Eric Laurent83b88082014-06-20 18:31:16 -0700218
Eric Laurent9b2064c2019-11-22 17:25:04 -0800219 // Call with AudioFlinger mLock held
220 std::map<audio_patch_handle_t, Patch>& patches_l() { return mPatches; }
221
222private:
Mikhail Naganovadca70f2018-07-09 12:49:25 -0700223 AudioHwDevice* findAudioHwDeviceByModule(audio_module_handle_t module);
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700224 sp<DeviceHalInterface> findHwDeviceByModule(audio_module_handle_t module);
Mikhail Naganovadca70f2018-07-09 12:49:25 -0700225 void addSoftwarePatchToInsertedModules(
226 audio_module_handle_t module, audio_patch_handle_t handle);
227 void removeSoftwarePatchFromInsertedModules(audio_patch_handle_t handle);
Eric Laurent9b2064c2019-11-22 17:25:04 -0800228 void erasePatch(audio_patch_handle_t handle);
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700229
Mikhail Naganovdea53042018-04-26 13:10:21 -0700230 AudioFlinger &mAudioFlinger;
231 std::map<audio_patch_handle_t, Patch> mPatches;
Mikhail Naganovadca70f2018-07-09 12:49:25 -0700232
233 // This map allows going from a thread to "downstream" software patches
234 // when a processing module inserted in between. Example:
235 //
236 // from map value.streams map key
237 // [Mixer thread] --> [Virtual output device] --> [Processing module] ---\
238 // [Harware module] <-- [Physical output device] <-- [S/W Patch] <--/
239 // from map value.sw_patches
240 //
241 // This allows the mixer thread to look up the threads of the software patch
242 // for propagating timing info, parameters, etc.
243 //
244 // The current assumptions are:
245 // 1) The processing module acts as a mixer with several outputs which
246 // represent differently downmixed and / or encoded versions of the same
247 // mixed stream. There is no 1:1 correspondence between the input streams
248 // and the software patches, but rather a N:N correspondence between
249 // a group of streams and a group of patches.
250 // 2) There are only a couple of inserted processing modules in the system,
251 // so when looking for a stream or patch handle we can iterate over
252 // all modules.
253 struct ModuleConnections {
254 std::set<audio_io_handle_t> streams;
255 std::set<audio_patch_handle_t> sw_patches;
256 };
257 std::map<audio_module_handle_t, ModuleConnections> mInsertedModules;
Eric Laurent1c333e22014-05-20 10:48:17 -0700258};