blob: 269a39831533d9c8a1fb1be8d4b06ed080182f05 [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;
38 audio_io_handle_t getPlaybackThreadHandle() const { return mPlaybackThreadHandle; };
39 audio_io_handle_t getRecordThreadHandle() const { return mRecordThreadHandle; };
40 private:
41 const PatchPanel &mPatchPanel;
42 const audio_patch_handle_t mPatchHandle;
43 const audio_io_handle_t mPlaybackThreadHandle;
44 const audio_io_handle_t mRecordThreadHandle;
45 };
46
Mikhail Naganovdea53042018-04-26 13:10:21 -070047 explicit PatchPanel(AudioFlinger* audioFlinger) : mAudioFlinger(*audioFlinger) {}
Eric Laurent1c333e22014-05-20 10:48:17 -070048
49 /* List connected audio ports and their attributes */
50 status_t listAudioPorts(unsigned int *num_ports,
51 struct audio_port *ports);
52
53 /* Get supported attributes for a given audio port */
54 status_t getAudioPort(struct audio_port *port);
55
56 /* Create a patch between several source and sink ports */
57 status_t createAudioPatch(const struct audio_patch *patch,
58 audio_patch_handle_t *handle);
59
60 /* Release a patch */
61 status_t releaseAudioPatch(audio_patch_handle_t handle);
62
63 /* List connected audio devices and they attributes */
64 status_t listAudioPatches(unsigned int *num_patches,
65 struct audio_patch *patches);
66
Mikhail Naganovadca70f2018-07-09 12:49:25 -070067 // Retrieves all currently estrablished software patches for a stream
68 // opened on an intermediate module.
69 status_t getDownstreamSoftwarePatches(audio_io_handle_t stream,
70 std::vector<SoftwarePatch> *patches) const;
71
72 // Notifies patch panel about all opened and closed streams.
73 void notifyStreamOpened(AudioHwDevice *audioHwDevice, audio_io_handle_t stream);
74 void notifyStreamClosed(audio_io_handle_t stream);
75
76 void dump(int fd) const;
Mikhail Naganov201369b2018-05-16 16:52:32 -070077
Mikhail Naganovdea53042018-04-26 13:10:21 -070078private:
Mikhail Naganov444ecc32018-05-01 17:40:05 -070079 template<typename ThreadType, typename TrackType>
80 class Endpoint {
81 public:
Mikhail Naganov9dfa2642018-05-10 10:09:19 -070082 Endpoint() = default;
83 Endpoint(Endpoint&& other) { *this = std::move(other); }
84 Endpoint& operator=(Endpoint&& other) {
85 ALOGE_IF(mHandle != AUDIO_PATCH_HANDLE_NONE,
86 "A non empty Patch Endpoint leaked, handle %d", mHandle);
87 *this = other;
88 other.mHandle = AUDIO_PATCH_HANDLE_NONE;
89 return *this;
90 }
91
Mikhail Naganov444ecc32018-05-01 17:40:05 -070092 status_t checkTrack(TrackType *trackOrNull) const {
93 if (trackOrNull == nullptr) return NO_MEMORY;
94 return trackOrNull->initCheck();
95 }
96 audio_patch_handle_t handle() const { return mHandle; }
97 sp<ThreadType> thread() { return mThread; }
98 sp<TrackType> track() { return mTrack; }
Mikhail Naganovadca70f2018-07-09 12:49:25 -070099 sp<const ThreadType> const_thread() const { return mThread; }
Andy Hungc3ab7732018-06-01 13:46:29 -0700100 sp<const TrackType> const_track() const { return mTrack; }
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700101
102 void closeConnections(PatchPanel *panel) {
103 if (mHandle != AUDIO_PATCH_HANDLE_NONE) {
104 panel->releaseAudioPatch(mHandle);
105 mHandle = AUDIO_PATCH_HANDLE_NONE;
106 }
107 if (mThread != 0) {
108 if (mTrack != 0) {
109 mThread->deletePatchTrack(mTrack);
110 }
111 if (mCloseThread) {
112 panel->mAudioFlinger.closeThreadInternal_l(mThread);
113 }
114 }
115 }
116 audio_patch_handle_t* handlePtr() { return &mHandle; }
117 void setThread(const sp<ThreadType>& thread, bool closeThread = true) {
118 mThread = thread;
119 mCloseThread = closeThread;
120 }
121 void setTrackAndPeer(const sp<TrackType>& track,
122 ThreadBase::PatchProxyBufferProvider *peer) {
123 mTrack = track;
124 mThread->addPatchTrack(mTrack);
125 mTrack->setPeerProxy(peer);
126 }
127 void stopTrack() { if (mTrack) mTrack->stop(); }
128
129 private:
Mikhail Naganov9dfa2642018-05-10 10:09:19 -0700130 Endpoint(const Endpoint&) = default;
131 Endpoint& operator=(const Endpoint&) = default;
132
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700133 sp<ThreadType> mThread;
134 bool mCloseThread = true;
135 audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
136 sp<TrackType> mTrack;
137 };
138
Eric Laurent1c333e22014-05-20 10:48:17 -0700139 class Patch {
140 public:
Mikhail Naganovdea53042018-04-26 13:10:21 -0700141 explicit Patch(const struct audio_patch &patch) : mAudioPatch(patch) {}
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700142 ~Patch();
Mikhail Naganov9dfa2642018-05-10 10:09:19 -0700143 Patch(const Patch&) = delete;
144 Patch(Patch&&) = default;
145 Patch& operator=(const Patch&) = delete;
146 Patch& operator=(Patch&&) = default;
Eric Laurent1c333e22014-05-20 10:48:17 -0700147
Mikhail Naganovdea53042018-04-26 13:10:21 -0700148 status_t createConnections(PatchPanel *panel);
149 void clearConnections(PatchPanel *panel);
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700150 bool isSoftware() const {
151 return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
152 mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; }
Mikhail Naganovdea53042018-04-26 13:10:21 -0700153
Andy Hungc3ab7732018-06-01 13:46:29 -0700154 // returns the latency of the patch (from record to playback).
155 status_t getLatencyMs(double *latencyMs) const;
156
Mikhail Naganovadca70f2018-07-09 12:49:25 -0700157 String8 dump(audio_patch_handle_t myHandle) const;
Mikhail Naganov201369b2018-05-16 16:52:32 -0700158
Mikhail Naganovdea53042018-04-26 13:10:21 -0700159 // Note that audio_patch::id is only unique within a HAL module
Eric Laurent83b88082014-06-20 18:31:16 -0700160 struct audio_patch mAudioPatch;
Eric Laurentb997d3a2016-06-07 18:23:45 -0700161 // handle for audio HAL patch handle present only when the audio HAL version is >= 3.0
Mikhail Naganovdea53042018-04-26 13:10:21 -0700162 audio_patch_handle_t mHalHandle = AUDIO_PATCH_HANDLE_NONE;
Eric Laurentb997d3a2016-06-07 18:23:45 -0700163 // below members are used by a software audio patch connecting a source device from a
164 // given audio HW module to a sink device on an other audio HW module.
Mikhail Naganovdea53042018-04-26 13:10:21 -0700165 // the objects are created by createConnections() and released by clearConnections()
166 // playback thread is created if no existing playback thread can be used
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700167 // connects playback thread output to sink device
168 Endpoint<PlaybackThread, PlaybackThread::PatchTrack> mPlayback;
169 // connects source device to record thread input
170 Endpoint<RecordThread, RecordThread::PatchRecord> mRecord;
Eric Laurent1c333e22014-05-20 10:48:17 -0700171 };
Eric Laurent83b88082014-06-20 18:31:16 -0700172
Mikhail Naganovadca70f2018-07-09 12:49:25 -0700173 AudioHwDevice* findAudioHwDeviceByModule(audio_module_handle_t module);
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700174 sp<DeviceHalInterface> findHwDeviceByModule(audio_module_handle_t module);
Mikhail Naganovadca70f2018-07-09 12:49:25 -0700175 void addSoftwarePatchToInsertedModules(
176 audio_module_handle_t module, audio_patch_handle_t handle);
177 void removeSoftwarePatchFromInsertedModules(audio_patch_handle_t handle);
Mikhail Naganov444ecc32018-05-01 17:40:05 -0700178
Mikhail Naganovdea53042018-04-26 13:10:21 -0700179 AudioFlinger &mAudioFlinger;
180 std::map<audio_patch_handle_t, Patch> mPatches;
Mikhail Naganovadca70f2018-07-09 12:49:25 -0700181
182 // This map allows going from a thread to "downstream" software patches
183 // when a processing module inserted in between. Example:
184 //
185 // from map value.streams map key
186 // [Mixer thread] --> [Virtual output device] --> [Processing module] ---\
187 // [Harware module] <-- [Physical output device] <-- [S/W Patch] <--/
188 // from map value.sw_patches
189 //
190 // This allows the mixer thread to look up the threads of the software patch
191 // for propagating timing info, parameters, etc.
192 //
193 // The current assumptions are:
194 // 1) The processing module acts as a mixer with several outputs which
195 // represent differently downmixed and / or encoded versions of the same
196 // mixed stream. There is no 1:1 correspondence between the input streams
197 // and the software patches, but rather a N:N correspondence between
198 // a group of streams and a group of patches.
199 // 2) There are only a couple of inserted processing modules in the system,
200 // so when looking for a stream or patch handle we can iterate over
201 // all modules.
202 struct ModuleConnections {
203 std::set<audio_io_handle_t> streams;
204 std::set<audio_patch_handle_t> sw_patches;
205 };
206 std::map<audio_module_handle_t, ModuleConnections> mInsertedModules;
Eric Laurent1c333e22014-05-20 10:48:17 -0700207};