• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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