1 /* 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 22 23 // PatchPanel is concealed within AudioFlinger, their lifetimes are the same. 24 class PatchPanel { 25 public: 26 class SoftwarePatch { 27 public: SoftwarePatch(const PatchPanel & patchPanel,audio_patch_handle_t patchHandle,audio_io_handle_t playbackThreadHandle,audio_io_handle_t recordThreadHandle)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; getPatchHandle()38 audio_patch_handle_t getPatchHandle() const { return mPatchHandle; }; getPlaybackThreadHandle()39 audio_io_handle_t getPlaybackThreadHandle() const { return mPlaybackThreadHandle; }; getRecordThreadHandle()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 PatchPanel(AudioFlinger * audioFlinger)48 explicit PatchPanel(AudioFlinger* audioFlinger) : mAudioFlinger(*audioFlinger) {} 49 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_v7 *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 bool endpointPatch = false); 61 62 /* Release a patch */ 63 status_t releaseAudioPatch(audio_patch_handle_t handle); 64 65 /* List connected audio devices and they attributes */ 66 status_t listAudioPatches(unsigned int *num_patches, 67 struct audio_patch *patches); 68 69 // Retrieves all currently estrablished software patches for a stream 70 // opened on an intermediate module. 71 status_t getDownstreamSoftwarePatches(audio_io_handle_t stream, 72 std::vector<SoftwarePatch> *patches) const; 73 74 // Notifies patch panel about all opened and closed streams. 75 void notifyStreamOpened(AudioHwDevice *audioHwDevice, audio_io_handle_t stream, 76 struct audio_patch *patch); 77 void notifyStreamClosed(audio_io_handle_t stream); 78 79 void dump(int fd) const; 80 81 template<typename ThreadType, typename TrackType> 82 class Endpoint final { 83 public: 84 Endpoint() = default; 85 Endpoint(const Endpoint&) = delete; 86 Endpoint& operator=(const Endpoint& other) noexcept { 87 mThread = other.mThread; 88 mCloseThread = other.mCloseThread; 89 mHandle = other.mHandle; 90 mTrack = other.mTrack; 91 return *this; 92 } Endpoint(Endpoint && other)93 Endpoint(Endpoint&& other) noexcept { swap(other); } 94 Endpoint& operator=(Endpoint&& other) noexcept { 95 swap(other); 96 return *this; 97 } ~Endpoint()98 ~Endpoint() { 99 ALOGE_IF(mHandle != AUDIO_PATCH_HANDLE_NONE, 100 "A non empty Patch Endpoint leaked, handle %d", mHandle); 101 } 102 checkTrack(TrackType * trackOrNull)103 status_t checkTrack(TrackType *trackOrNull) const { 104 if (trackOrNull == nullptr) return NO_MEMORY; 105 return trackOrNull->initCheck(); 106 } handle()107 audio_patch_handle_t handle() const { return mHandle; } thread()108 sp<ThreadType> thread() const { return mThread; } track()109 sp<TrackType> track() const { return mTrack; } const_thread()110 sp<const ThreadType> const_thread() const { return mThread; } const_track()111 sp<const TrackType> const_track() const { return mTrack; } 112 closeConnections(PatchPanel * panel)113 void closeConnections(PatchPanel *panel) { 114 if (mHandle != AUDIO_PATCH_HANDLE_NONE) { 115 panel->releaseAudioPatch(mHandle); 116 mHandle = AUDIO_PATCH_HANDLE_NONE; 117 } 118 if (mThread != 0) { 119 if (mTrack != 0) { 120 mThread->deletePatchTrack(mTrack); 121 } 122 if (mCloseThread) { 123 panel->mAudioFlinger.closeThreadInternal_l(mThread); 124 } 125 } 126 } handlePtr()127 audio_patch_handle_t* handlePtr() { return &mHandle; } 128 void setThread(const sp<ThreadType>& thread, bool closeThread = true) { 129 mThread = thread; 130 mCloseThread = closeThread; 131 } 132 template <typename T> setTrackAndPeer(const sp<TrackType> & track,const sp<T> & peer,bool holdReference)133 void setTrackAndPeer(const sp<TrackType>& track, const sp<T> &peer, bool holdReference) { 134 mTrack = track; 135 mThread->addPatchTrack(mTrack); 136 mTrack->setPeerProxy(peer, holdReference); 137 mClearPeerProxy = holdReference; 138 } clearTrackPeer()139 void clearTrackPeer() { if (mClearPeerProxy && mTrack) mTrack->clearPeerProxy(); } stopTrack()140 void stopTrack() { if (mTrack) mTrack->stop(); } 141 swap(Endpoint & other)142 void swap(Endpoint &other) noexcept { 143 using std::swap; 144 swap(mThread, other.mThread); 145 swap(mCloseThread, other.mCloseThread); 146 swap(mClearPeerProxy, other.mClearPeerProxy); 147 swap(mHandle, other.mHandle); 148 swap(mTrack, other.mTrack); 149 } 150 swap(Endpoint & a,Endpoint & b)151 friend void swap(Endpoint &a, Endpoint &b) noexcept { 152 a.swap(b); 153 } 154 155 private: 156 sp<ThreadType> mThread; 157 bool mCloseThread = true; 158 bool mClearPeerProxy = true; 159 audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE; 160 sp<TrackType> mTrack; 161 }; 162 163 class Patch final { 164 public: Patch(const struct audio_patch & patch,bool endpointPatch)165 Patch(const struct audio_patch &patch, bool endpointPatch) : 166 mAudioPatch(patch), mIsEndpointPatch(endpointPatch) {} 167 Patch() = default; 168 ~Patch(); Patch(const Patch & other)169 Patch(const Patch& other) noexcept { 170 mAudioPatch = other.mAudioPatch; 171 mHalHandle = other.mHalHandle; 172 mPlayback = other.mPlayback; 173 mRecord = other.mRecord; 174 mThread = other.mThread; 175 mIsEndpointPatch = other.mIsEndpointPatch; 176 } Patch(Patch && other)177 Patch(Patch&& other) noexcept { swap(other); } 178 Patch& operator=(Patch&& other) noexcept { 179 swap(other); 180 return *this; 181 } 182 swap(Patch & other)183 void swap(Patch &other) noexcept { 184 using std::swap; 185 swap(mAudioPatch, other.mAudioPatch); 186 swap(mHalHandle, other.mHalHandle); 187 swap(mPlayback, other.mPlayback); 188 swap(mRecord, other.mRecord); 189 swap(mThread, other.mThread); 190 swap(mIsEndpointPatch, other.mIsEndpointPatch); 191 } 192 swap(Patch & a,Patch & b)193 friend void swap(Patch &a, Patch &b) noexcept { 194 a.swap(b); 195 } 196 197 status_t createConnections(PatchPanel *panel); 198 void clearConnections(PatchPanel *panel); isSoftware()199 bool isSoftware() const { 200 return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE || 201 mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; } 202 setThread(sp<ThreadBase> thread)203 void setThread(sp<ThreadBase> thread) { mThread = thread; } thread()204 wp<ThreadBase> thread() const { return mThread; } 205 206 // returns the latency of the patch (from record to playback). 207 status_t getLatencyMs(double *latencyMs) const; 208 209 String8 dump(audio_patch_handle_t myHandle) const; 210 211 // Note that audio_patch::id is only unique within a HAL module 212 struct audio_patch mAudioPatch; 213 // handle for audio HAL patch handle present only when the audio HAL version is >= 3.0 214 audio_patch_handle_t mHalHandle = AUDIO_PATCH_HANDLE_NONE; 215 // below members are used by a software audio patch connecting a source device from a 216 // given audio HW module to a sink device on an other audio HW module. 217 // the objects are created by createConnections() and released by clearConnections() 218 // playback thread is created if no existing playback thread can be used 219 // connects playback thread output to sink device 220 Endpoint<PlaybackThread, PlaybackThread::PatchTrack> mPlayback; 221 // connects source device to record thread input 222 Endpoint<RecordThread, RecordThread::PatchRecord> mRecord; 223 224 wp<ThreadBase> mThread; 225 bool mIsEndpointPatch; 226 }; 227 228 // Call with AudioFlinger mLock held patches_l()229 std::map<audio_patch_handle_t, Patch>& patches_l() { return mPatches; } 230 231 private: 232 AudioHwDevice* findAudioHwDeviceByModule(audio_module_handle_t module); 233 sp<DeviceHalInterface> findHwDeviceByModule(audio_module_handle_t module); 234 void addSoftwarePatchToInsertedModules( 235 audio_module_handle_t module, audio_patch_handle_t handle, 236 const struct audio_patch *patch); 237 void removeSoftwarePatchFromInsertedModules(audio_patch_handle_t handle); 238 void erasePatch(audio_patch_handle_t handle); 239 240 AudioFlinger &mAudioFlinger; 241 std::map<audio_patch_handle_t, Patch> mPatches; 242 243 // This map allows going from a thread to "downstream" software patches 244 // when a processing module inserted in between. Example: 245 // 246 // from map value.streams map key 247 // [Mixer thread] --> [Virtual output device] --> [Processing module] ---\ 248 // [Harware module] <-- [Physical output device] <-- [S/W Patch] <--/ 249 // from map value.sw_patches 250 // 251 // This allows the mixer thread to look up the threads of the software patch 252 // for propagating timing info, parameters, etc. 253 // 254 // The current assumptions are: 255 // 1) The processing module acts as a mixer with several outputs which 256 // represent differently downmixed and / or encoded versions of the same 257 // mixed stream. There is no 1:1 correspondence between the input streams 258 // and the software patches, but rather a N:N correspondence between 259 // a group of streams and a group of patches. 260 // 2) There are only a couple of inserted processing modules in the system, 261 // so when looking for a stream or patch handle we can iterate over 262 // all modules. 263 struct ModuleConnections { 264 std::set<audio_io_handle_t> streams; 265 std::set<audio_patch_handle_t> sw_patches; 266 }; 267 std::map<audio_module_handle_t, ModuleConnections> mInsertedModules; 268 }; 269