/* * Copyright (C) 2018 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. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include "AudioPatch.h" #include "EffectDescriptor.h" namespace android { class DeviceDescriptor; class HwAudioOutputDescriptor; class SwAudioOutputDescriptor; class ClientDescriptor: public RefBase { public: ClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_session_t sessionId, audio_attributes_t attributes, audio_config_base_t config, audio_port_handle_t preferredDeviceId, bool isPreferredDeviceForExclusiveUse = false) : mPortId(portId), mUid(uid), mSessionId(sessionId), mAttributes(attributes), mConfig(config), mPreferredDeviceId(preferredDeviceId), mActive(false), mPreferredDeviceForExclusiveUse(isPreferredDeviceForExclusiveUse){} ~ClientDescriptor() override = default; virtual void dump(String8 *dst, int spaces, int index) const; virtual std::string toShortString() const; audio_port_handle_t portId() const { return mPortId; } uid_t uid() const { return mUid; } audio_session_t session() const { return mSessionId; }; audio_attributes_t attributes() const { return mAttributes; } audio_config_base_t config() const { return mConfig; } audio_port_handle_t preferredDeviceId() const { return mPreferredDeviceId; }; void setPreferredDeviceId(audio_port_handle_t preferredDeviceId) { mPreferredDeviceId = preferredDeviceId; } bool isPreferredDeviceForExclusiveUse() const { return mPreferredDeviceForExclusiveUse; } virtual void setActive(bool active) { mActive = active; } bool active() const { return mActive; } bool hasPreferredDevice(bool activeOnly = false) const { return mPreferredDeviceId != AUDIO_PORT_HANDLE_NONE && (!activeOnly || mActive); } private: const audio_port_handle_t mPortId; // unique Id for this client const uid_t mUid; // client UID const audio_session_t mSessionId; // audio session ID const audio_attributes_t mAttributes; // usage... const audio_config_base_t mConfig; audio_port_handle_t mPreferredDeviceId; // selected input device port ID bool mActive; bool mPreferredDeviceForExclusiveUse = false; }; class TrackClientDescriptor: public ClientDescriptor { public: TrackClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_session_t sessionId, audio_attributes_t attributes, audio_config_base_t config, audio_port_handle_t preferredDeviceId, audio_stream_type_t stream, product_strategy_t strategy, VolumeSource volumeSource, audio_output_flags_t flags, bool isPreferredDeviceForExclusiveUse, std::vector> secondaryOutputs) : ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId, isPreferredDeviceForExclusiveUse), mStream(stream), mStrategy(strategy), mVolumeSource(volumeSource), mFlags(flags), mSecondaryOutputs(std::move(secondaryOutputs)) {} ~TrackClientDescriptor() override = default; using ClientDescriptor::dump; void dump(String8 *dst, int spaces, int index) const override; std::string toShortString() const override; audio_output_flags_t flags() const { return mFlags; } audio_stream_type_t stream() const { return mStream; } product_strategy_t strategy() const { return mStrategy; } const std::vector>& getSecondaryOutputs() const { return mSecondaryOutputs; }; VolumeSource volumeSource() const { return mVolumeSource; } void setActive(bool active) override { int delta = active ? 1 : -1; changeActivityCount(delta); } void changeActivityCount(int delta) { if (delta > 0) { mActivityCount += delta; } else { LOG_ALWAYS_FATAL_IF(!mActivityCount, "%s(%s) invalid delta %d, inactive client", __func__, toShortString().c_str(), delta); LOG_ALWAYS_FATAL_IF(static_cast(mActivityCount) < -delta, "%s(%s) invalid delta %d, active client count %d", __func__, toShortString().c_str(), delta, mActivityCount); mActivityCount += delta; } ClientDescriptor::setActive(mActivityCount > 0); } uint32_t getActivityCount() const { return mActivityCount; } private: const audio_stream_type_t mStream; const product_strategy_t mStrategy; const VolumeSource mVolumeSource; const audio_output_flags_t mFlags; const std::vector> mSecondaryOutputs; /** * required for duplicating thread, prevent from removing active client from an output * involved in a duplication. */ uint32_t mActivityCount = 0; }; class RecordClientDescriptor: public ClientDescriptor { public: RecordClientDescriptor(audio_port_handle_t portId, audio_unique_id_t riid, uid_t uid, audio_session_t sessionId, audio_attributes_t attributes, audio_config_base_t config, audio_port_handle_t preferredDeviceId, audio_source_t source, audio_input_flags_t flags, bool isSoundTrigger) : ClientDescriptor(portId, uid, sessionId, attributes, config, preferredDeviceId), mRIId(riid), mSource(source), mFlags(flags), mIsSoundTrigger(isSoundTrigger), mAppState(APP_STATE_IDLE) {} ~RecordClientDescriptor() override = default; using ClientDescriptor::dump; void dump(String8 *dst, int spaces, int index) const override; audio_unique_id_t riid() const { return mRIId; } audio_source_t source() const { return mSource; } audio_input_flags_t flags() const { return mFlags; } bool isSoundTrigger() const { return mIsSoundTrigger; } bool isLowLevel() const { return mRIId == RECORD_RIID_INVALID; } void setAppState(app_state_t appState) { mAppState = appState; } app_state_t appState() { return mAppState; } bool isSilenced() const { return mAppState == APP_STATE_IDLE; } void trackEffectEnabled(const sp &effect, bool enabled); EffectDescriptorCollection getEnabledEffects() const { return mEnabledEffects; } private: const audio_unique_id_t mRIId; const audio_source_t mSource; const audio_input_flags_t mFlags; const bool mIsSoundTrigger; app_state_t mAppState; EffectDescriptorCollection mEnabledEffects; }; class SourceClientDescriptor: public TrackClientDescriptor { public: SourceClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes, const sp& patchDesc, const sp& srcDevice, audio_stream_type_t stream, product_strategy_t strategy, VolumeSource volumeSource); ~SourceClientDescriptor() override = default; sp patchDesc() const { return mPatchDesc; } sp srcDevice() const { return mSrcDevice; }; wp swOutput() const { return mSwOutput; } void setSwOutput(const sp& swOutput); wp hwOutput() const { return mHwOutput; } void setHwOutput(const sp& hwOutput); using ClientDescriptor::dump; void dump(String8 *dst, int spaces, int index) const override; private: const sp mPatchDesc; const sp mSrcDevice; wp mSwOutput; wp mHwOutput; }; class SourceClientCollection : public DefaultKeyedVector< audio_port_handle_t, sp > { public: void dump(String8 *dst) const; }; typedef std::vector< sp > TrackClientVector; typedef std::vector< sp > RecordClientVector; // A Map that associates a portId with a client (type T) // which is either TrackClientDescriptor or RecordClientDescriptor. template class ClientMapHandler { public: virtual ~ClientMapHandler() = default; // Track client management virtual void addClient(const sp &client) { const audio_port_handle_t portId = client->portId(); LOG_ALWAYS_FATAL_IF(!mClients.emplace(portId, client).second, "%s(%d): attempting to add client that already exists", __func__, portId); } sp getClient(audio_port_handle_t portId) const { auto it = mClients.find(portId); if (it == mClients.end()) return nullptr; return it->second; } virtual void removeClient(audio_port_handle_t portId) { auto it = mClients.find(portId); LOG_ALWAYS_FATAL_IF(it == mClients.end(), "%s(%d): client does not exist", __func__, portId); LOG_ALWAYS_FATAL_IF(it->second->active(), "%s(%d): removing client still active!", __func__, portId); (void)mClients.erase(it); } size_t getClientCount() const { return mClients.size(); } virtual void dump(String8 *dst) const { size_t index = 0; for (const auto& client: getClientIterable()) { client->dump(dst, 2, index++); } } // helper types using ClientMap = std::map>; using ClientMapIterator = typename ClientMap::const_iterator; // ClientMap is const qualified class ClientIterable { public: explicit ClientIterable(const ClientMapHandler &ref) : mClientMapHandler(ref) { } class iterator { public: // traits using iterator_category = std::forward_iterator_tag; using value_type = sp; using difference_type = ptrdiff_t; using pointer = const sp*; // Note: const using reference = const sp&; // Note: const // implementation explicit iterator(const ClientMapIterator &it) : mIt(it) { } iterator& operator++() /* prefix */ { ++mIt; return *this; } reference operator* () const { return mIt->second; } reference operator->() const { return mIt->second; } // as if sp<> difference_type operator-(const iterator& rhs) {return mIt - rhs.mIt; } bool operator==(const iterator& rhs) const { return mIt == rhs.mIt; } bool operator!=(const iterator& rhs) const { return mIt != rhs.mIt; } private: ClientMapIterator mIt; }; iterator begin() const { return iterator{mClientMapHandler.mClients.begin()}; } iterator end() const { return iterator{mClientMapHandler.mClients.end()}; } private: const ClientMapHandler& mClientMapHandler; // iterating does not modify map. }; // return an iterable object that can be used in a range-based-for to enumerate clients. // this iterable does not allow modification, it should be used as a temporary. ClientIterable getClientIterable() const { return ClientIterable{*this}; } private: // ClientMap maps a portId to a client descriptor (both uniquely identify each other). ClientMap mClients; }; } // namespace android