123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221 |
- /*
- **
- ** Copyright 2014, The Android Open Source Project
- **
- ** Licensed under the Apache License, Version 2.0 (the "License");
- ** you may not use this file except in compliance with the License.
- ** You may obtain a copy of the License at
- **
- ** http://www.apache.org/licenses/LICENSE-2.0
- **
- ** Unless required by applicable law or agreed to in writing, software
- ** distributed under the License is distributed on an "AS IS" BASIS,
- ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ** See the License for the specific language governing permissions and
- ** limitations under the License.
- */
- #ifndef INCLUDING_FROM_AUDIOFLINGER_H
- #error This header file should only be included from AudioFlinger.h
- #endif
- // PatchPanel is concealed within AudioFlinger, their lifetimes are the same.
- class PatchPanel {
- public:
- class SoftwarePatch {
- public:
- SoftwarePatch(const PatchPanel &patchPanel, audio_patch_handle_t patchHandle,
- audio_io_handle_t playbackThreadHandle, audio_io_handle_t recordThreadHandle)
- : mPatchPanel(patchPanel), mPatchHandle(patchHandle),
- mPlaybackThreadHandle(playbackThreadHandle),
- mRecordThreadHandle(recordThreadHandle) {}
- SoftwarePatch(const SoftwarePatch&) = default;
- SoftwarePatch& operator=(const SoftwarePatch&) = default;
- // Must be called under AudioFlinger::mLock
- status_t getLatencyMs_l(double *latencyMs) const;
- audio_patch_handle_t getPatchHandle() const { return mPatchHandle; };
- audio_io_handle_t getPlaybackThreadHandle() const { return mPlaybackThreadHandle; };
- audio_io_handle_t getRecordThreadHandle() const { return mRecordThreadHandle; };
- private:
- const PatchPanel &mPatchPanel;
- const audio_patch_handle_t mPatchHandle;
- const audio_io_handle_t mPlaybackThreadHandle;
- const audio_io_handle_t mRecordThreadHandle;
- };
- explicit PatchPanel(AudioFlinger* audioFlinger) : mAudioFlinger(*audioFlinger) {}
- /* List connected audio ports and their attributes */
- status_t listAudioPorts(unsigned int *num_ports,
- struct audio_port *ports);
- /* Get supported attributes for a given audio port */
- status_t getAudioPort(struct audio_port *port);
- /* Create a patch between several source and sink ports */
- status_t createAudioPatch(const struct audio_patch *patch,
- audio_patch_handle_t *handle);
- /* Release a patch */
- status_t releaseAudioPatch(audio_patch_handle_t handle);
- /* List connected audio devices and they attributes */
- status_t listAudioPatches(unsigned int *num_patches,
- struct audio_patch *patches);
- // Retrieves all currently estrablished software patches for a stream
- // opened on an intermediate module.
- status_t getDownstreamSoftwarePatches(audio_io_handle_t stream,
- std::vector<SoftwarePatch> *patches) const;
- // Notifies patch panel about all opened and closed streams.
- void notifyStreamOpened(AudioHwDevice *audioHwDevice, audio_io_handle_t stream);
- void notifyStreamClosed(audio_io_handle_t stream);
- void dump(int fd) const;
- private:
- template<typename ThreadType, typename TrackType>
- class Endpoint {
- public:
- Endpoint() = default;
- Endpoint(const Endpoint&) = delete;
- Endpoint& operator=(const Endpoint&) = delete;
- Endpoint(Endpoint&& other) noexcept { swap(other); }
- Endpoint& operator=(Endpoint&& other) noexcept {
- swap(other);
- return *this;
- }
- ~Endpoint() {
- ALOGE_IF(mHandle != AUDIO_PATCH_HANDLE_NONE,
- "A non empty Patch Endpoint leaked, handle %d", mHandle);
- }
- status_t checkTrack(TrackType *trackOrNull) const {
- if (trackOrNull == nullptr) return NO_MEMORY;
- return trackOrNull->initCheck();
- }
- audio_patch_handle_t handle() const { return mHandle; }
- sp<ThreadType> thread() { return mThread; }
- sp<TrackType> track() { return mTrack; }
- sp<const ThreadType> const_thread() const { return mThread; }
- sp<const TrackType> const_track() const { return mTrack; }
- void closeConnections(PatchPanel *panel) {
- if (mHandle != AUDIO_PATCH_HANDLE_NONE) {
- panel->releaseAudioPatch(mHandle);
- mHandle = AUDIO_PATCH_HANDLE_NONE;
- }
- if (mThread != 0) {
- if (mTrack != 0) {
- mThread->deletePatchTrack(mTrack);
- }
- if (mCloseThread) {
- panel->mAudioFlinger.closeThreadInternal_l(mThread);
- }
- }
- }
- audio_patch_handle_t* handlePtr() { return &mHandle; }
- void setThread(const sp<ThreadType>& thread, bool closeThread = true) {
- mThread = thread;
- mCloseThread = closeThread;
- }
- template <typename T>
- void setTrackAndPeer(const sp<TrackType>& track, const sp<T> &peer) {
- mTrack = track;
- mThread->addPatchTrack(mTrack);
- mTrack->setPeerProxy(peer, true /* holdReference */);
- }
- void clearTrackPeer() { if (mTrack) mTrack->clearPeerProxy(); }
- void stopTrack() { if (mTrack) mTrack->stop(); }
- void swap(Endpoint &other) noexcept {
- using std::swap;
- swap(mThread, other.mThread);
- swap(mCloseThread, other.mCloseThread);
- swap(mHandle, other.mHandle);
- swap(mTrack, other.mTrack);
- }
- friend void swap(Endpoint &a, Endpoint &b) noexcept {
- a.swap(b);
- }
- private:
- sp<ThreadType> mThread;
- bool mCloseThread = true;
- audio_patch_handle_t mHandle = AUDIO_PATCH_HANDLE_NONE;
- sp<TrackType> mTrack;
- };
- class Patch {
- public:
- explicit Patch(const struct audio_patch &patch) : mAudioPatch(patch) {}
- ~Patch();
- Patch(const Patch&) = delete;
- Patch(Patch&&) = default;
- Patch& operator=(const Patch&) = delete;
- Patch& operator=(Patch&&) = default;
- status_t createConnections(PatchPanel *panel);
- void clearConnections(PatchPanel *panel);
- bool isSoftware() const {
- return mRecord.handle() != AUDIO_PATCH_HANDLE_NONE ||
- mPlayback.handle() != AUDIO_PATCH_HANDLE_NONE; }
- // returns the latency of the patch (from record to playback).
- status_t getLatencyMs(double *latencyMs) const;
- String8 dump(audio_patch_handle_t myHandle) const;
- // Note that audio_patch::id is only unique within a HAL module
- struct audio_patch mAudioPatch;
- // handle for audio HAL patch handle present only when the audio HAL version is >= 3.0
- audio_patch_handle_t mHalHandle = AUDIO_PATCH_HANDLE_NONE;
- // below members are used by a software audio patch connecting a source device from a
- // given audio HW module to a sink device on an other audio HW module.
- // the objects are created by createConnections() and released by clearConnections()
- // playback thread is created if no existing playback thread can be used
- // connects playback thread output to sink device
- Endpoint<PlaybackThread, PlaybackThread::PatchTrack> mPlayback;
- // connects source device to record thread input
- Endpoint<RecordThread, RecordThread::PatchRecord> mRecord;
- };
- AudioHwDevice* findAudioHwDeviceByModule(audio_module_handle_t module);
- sp<DeviceHalInterface> findHwDeviceByModule(audio_module_handle_t module);
- void addSoftwarePatchToInsertedModules(
- audio_module_handle_t module, audio_patch_handle_t handle);
- void removeSoftwarePatchFromInsertedModules(audio_patch_handle_t handle);
- AudioFlinger &mAudioFlinger;
- std::map<audio_patch_handle_t, Patch> mPatches;
- // This map allows going from a thread to "downstream" software patches
- // when a processing module inserted in between. Example:
- //
- // from map value.streams map key
- // [Mixer thread] --> [Virtual output device] --> [Processing module] ---\
- // [Harware module] <-- [Physical output device] <-- [S/W Patch] <--/
- // from map value.sw_patches
- //
- // This allows the mixer thread to look up the threads of the software patch
- // for propagating timing info, parameters, etc.
- //
- // The current assumptions are:
- // 1) The processing module acts as a mixer with several outputs which
- // represent differently downmixed and / or encoded versions of the same
- // mixed stream. There is no 1:1 correspondence between the input streams
- // and the software patches, but rather a N:N correspondence between
- // a group of streams and a group of patches.
- // 2) There are only a couple of inserted processing modules in the system,
- // so when looking for a stream or patch handle we can iterate over
- // all modules.
- struct ModuleConnections {
- std::set<audio_io_handle_t> streams;
- std::set<audio_patch_handle_t> sw_patches;
- };
- std::map<audio_module_handle_t, ModuleConnections> mInsertedModules;
- };
|