| /* |
| * Copyright (C) 2015 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 |
| |
| #define __STDC_LIMIT_MACROS |
| #include <inttypes.h> |
| |
| #include <sys/types.h> |
| |
| #include <media/AudioContainers.h> |
| #include <utils/Errors.h> |
| #include <utils/Timers.h> |
| #include <utils/KeyedVector.h> |
| #include <system/audio.h> |
| #include "AudioIODescriptorInterface.h" |
| #include "ClientDescriptor.h" |
| #include "DeviceDescriptor.h" |
| #include "PolicyAudioPort.h" |
| #include <vector> |
| |
| namespace android { |
| |
| class IOProfile; |
| class AudioPolicyMix; |
| class AudioPolicyClientInterface; |
| |
| class ActivityTracking |
| { |
| public: |
| virtual ~ActivityTracking() = default; |
| bool isActive(uint32_t inPastMs = 0, nsecs_t sysTime = 0) const |
| { |
| if (mActivityCount > 0) { |
| return true; |
| } |
| if (inPastMs == 0) { |
| return false; |
| } |
| if (sysTime == 0) { |
| sysTime = systemTime(); |
| } |
| if (ns2ms(sysTime - mStopTime) < inPastMs) { |
| return true; |
| } |
| return false; |
| } |
| void changeActivityCount(int delta) |
| { |
| if ((delta + (int)mActivityCount) < 0) { |
| LOG_ALWAYS_FATAL("%s: invalid delta %d, refCount %d", __func__, delta, mActivityCount); |
| } |
| mActivityCount += delta; |
| if (!mActivityCount) { |
| setStopTime(systemTime()); |
| } |
| } |
| uint32_t getActivityCount() const { return mActivityCount; } |
| nsecs_t getStopTime() const { return mStopTime; } |
| void setStopTime(nsecs_t stopTime) { mStopTime = stopTime; } |
| |
| virtual void dump(String8 *dst, int spaces) const |
| { |
| dst->appendFormat("%*s- ActivityCount: %d, StopTime: %" PRId64 ", ", spaces, "", |
| getActivityCount(), getStopTime()); |
| } |
| private: |
| uint32_t mActivityCount = 0; |
| nsecs_t mStopTime = 0; |
| }; |
| |
| /** |
| * @brief VolumeActivity: it tracks the activity for volume policy (volume index, mute, |
| * memorize previous stop, and store mute if incompatible device with another strategy. |
| */ |
| class VolumeActivity : public ActivityTracking |
| { |
| public: |
| bool isMuted() const { return mMuteCount > 0; } |
| int getMuteCount() const { return mMuteCount; } |
| int incMuteCount() { return ++mMuteCount; } |
| int decMuteCount() { return mMuteCount > 0 ? --mMuteCount : -1; } |
| |
| void dump(String8 *dst, int spaces) const override |
| { |
| ActivityTracking::dump(dst, spaces); |
| dst->appendFormat(", Volume: %.03f, MuteCount: %02d\n", mCurVolumeDb, mMuteCount); |
| } |
| void setVolume(float volumeDb) { mCurVolumeDb = volumeDb; } |
| float getVolume() const { return mCurVolumeDb; } |
| |
| private: |
| int mMuteCount = 0; /**< mute request counter */ |
| float mCurVolumeDb = NAN; /**< current volume in dB. */ |
| }; |
| /** |
| * Note: volume activities shall be indexed by CurvesId if we want to allow multiple |
| * curves per volume source, inferring a mute management or volume balancing between HW and SW is |
| * done |
| */ |
| using VolumeActivities = std::map<VolumeSource, VolumeActivity>; |
| |
| /** |
| * @brief The Activity class: it tracks the activity for volume policy (volume index, mute, |
| * memorize previous stop, and store mute if incompatible device with another strategy. |
| * Having this class prevents from looping on all attributes (legacy streams) of the strategy |
| */ |
| class RoutingActivity : public ActivityTracking |
| { |
| public: |
| void setMutedByDevice( bool isMuted) { mIsMutedByDevice = isMuted; } |
| bool isMutedByDevice() const { return mIsMutedByDevice; } |
| |
| void dump(String8 *dst, int spaces) const override { |
| ActivityTracking::dump(dst, spaces); |
| dst->appendFormat("\n"); |
| } |
| private: |
| /** |
| * strategies muted because of incompatible device selection. |
| * See AudioPolicyManager::checkDeviceMuteStrategies() |
| */ |
| bool mIsMutedByDevice = false; |
| }; |
| using RoutingActivities = std::map<product_strategy_t, RoutingActivity>; |
| |
| // descriptor for audio outputs. Used to maintain current configuration of each opened audio output |
| // and keep track of the usage of this output by each audio stream type. |
| class AudioOutputDescriptor: public AudioPortConfig, |
| public PolicyAudioPortConfig, |
| public AudioIODescriptorInterface, |
| public ClientMapHandler<TrackClientDescriptor> |
| { |
| public: |
| AudioOutputDescriptor(const sp<PolicyAudioPort>& policyAudioPort, |
| AudioPolicyClientInterface *clientInterface); |
| virtual ~AudioOutputDescriptor() {} |
| |
| void dump(String8 *dst) const override; |
| void log(const char* indent); |
| |
| virtual DeviceVector devices() const { return mDevices; } |
| bool sharesHwModuleWith(const sp<AudioOutputDescriptor>& outputDesc); |
| virtual DeviceVector supportedDevices() const { return mDevices; } |
| virtual bool isDuplicated() const { return false; } |
| virtual uint32_t latency() { return 0; } |
| virtual bool isFixedVolume(const DeviceTypeSet& deviceTypes); |
| virtual bool setVolume(float volumeDb, bool muted, |
| VolumeSource volumeSource, const StreamTypeVector &streams, |
| const DeviceTypeSet& deviceTypes, |
| uint32_t delayMs, |
| bool force); |
| |
| /** |
| * @brief setStopTime set the stop time due to the client stoppage or a re routing of this |
| * client |
| * @param client to be considered |
| * @param sysTime when the client stopped/was rerouted |
| */ |
| void setStopTime(const sp<TrackClientDescriptor>& client, nsecs_t sysTime); |
| |
| /** |
| * Changes the client->active() state and the output descriptor's global active count, |
| * along with the stream active count and mActiveClients. |
| * The client must be previously added by the base class addClient(). |
| * In case of duplicating thread, client shall be added on the duplicated thread, not on the |
| * involved outputs but setClientActive will be called on all output to track strategy and |
| * active client for a given output. |
| * Active ref count of the client will be incremented/decremented through setActive API |
| */ |
| virtual void setClientActive(const sp<TrackClientDescriptor>& client, bool active); |
| bool isClientActive(const sp<TrackClientDescriptor>& client); |
| |
| bool isActive(uint32_t inPastMs) const; |
| bool isActive(VolumeSource volumeSource = VOLUME_SOURCE_NONE, |
| uint32_t inPastMs = 0, |
| nsecs_t sysTime = 0) const; |
| bool isAnyActive(VolumeSource volumeSourceToIgnore) const; |
| |
| std::vector<VolumeSource> getActiveVolumeSources() const { |
| std::vector<VolumeSource> activeList; |
| for (const auto &iter : mVolumeActivities) { |
| if (iter.second.isActive()) { |
| activeList.push_back(iter.first); |
| } |
| } |
| return activeList; |
| } |
| uint32_t getActivityCount(VolumeSource vs) const |
| { |
| return mVolumeActivities.find(vs) != std::end(mVolumeActivities)? |
| mVolumeActivities.at(vs).getActivityCount() : 0; |
| } |
| bool isMuted(VolumeSource vs) const |
| { |
| return mVolumeActivities.find(vs) != std::end(mVolumeActivities)? |
| mVolumeActivities.at(vs).isMuted() : false; |
| } |
| int getMuteCount(VolumeSource vs) const |
| { |
| return mVolumeActivities.find(vs) != std::end(mVolumeActivities)? |
| mVolumeActivities.at(vs).getMuteCount() : 0; |
| } |
| int incMuteCount(VolumeSource vs) |
| { |
| return mVolumeActivities[vs].incMuteCount(); |
| } |
| int decMuteCount(VolumeSource vs) |
| { |
| return mVolumeActivities[vs].decMuteCount(); |
| } |
| void setCurVolume(VolumeSource vs, float volumeDb) |
| { |
| // Even if not activity for this source registered, need to create anyway |
| mVolumeActivities[vs].setVolume(volumeDb); |
| } |
| float getCurVolume(VolumeSource vs) const |
| { |
| return mVolumeActivities.find(vs) != std::end(mVolumeActivities) ? |
| mVolumeActivities.at(vs).getVolume() : NAN; |
| } |
| |
| bool isStrategyActive(product_strategy_t ps, uint32_t inPastMs = 0, nsecs_t sysTime = 0) const |
| { |
| return mRoutingActivities.find(ps) != std::end(mRoutingActivities)? |
| mRoutingActivities.at(ps).isActive(inPastMs, sysTime) : false; |
| } |
| bool isStrategyMutedByDevice(product_strategy_t ps) const |
| { |
| return mRoutingActivities.find(ps) != std::end(mRoutingActivities)? |
| mRoutingActivities.at(ps).isMutedByDevice() : false; |
| } |
| void setStrategyMutedByDevice(product_strategy_t ps, bool isMuted) |
| { |
| mRoutingActivities[ps].setMutedByDevice(isMuted); |
| } |
| |
| // PolicyAudioPortConfig |
| virtual sp<PolicyAudioPort> getPolicyAudioPort() const |
| { |
| return mPolicyAudioPort; |
| } |
| |
| // AudioPortConfig |
| virtual status_t applyAudioPortConfig(const struct audio_port_config *config, |
| struct audio_port_config *backupConfig = NULL); |
| virtual void toAudioPortConfig(struct audio_port_config *dstConfig, |
| const struct audio_port_config *srcConfig = NULL) const; |
| virtual sp<AudioPort> getAudioPort() const { return mPolicyAudioPort->asAudioPort(); } |
| |
| virtual void toAudioPort(struct audio_port_v7 *port) const; |
| |
| audio_module_handle_t getModuleHandle() const; |
| |
| // implementation of AudioIODescriptorInterface |
| audio_config_base_t getConfig() const override; |
| audio_patch_handle_t getPatchHandle() const override; |
| void setPatchHandle(audio_patch_handle_t handle) override; |
| bool isMmap() override { |
| if (getPolicyAudioPort() != nullptr) { |
| return getPolicyAudioPort()->isMmap(); |
| } |
| return false; |
| } |
| |
| TrackClientVector clientsList(bool activeOnly = false, |
| product_strategy_t strategy = PRODUCT_STRATEGY_NONE, |
| bool preferredDeviceOnly = false) const; |
| |
| // override ClientMapHandler to abort when removing a client when active. |
| void removeClient(audio_port_handle_t portId) override { |
| auto client = getClient(portId); |
| LOG_ALWAYS_FATAL_IF(client.get() == nullptr, |
| "%s(%d): nonexistent client portId %d", __func__, mId, portId); |
| // it is possible that when a client is removed, we could remove its |
| // associated active count by calling changeStreamActiveCount(), |
| // but that would be hiding a problem, so we log fatal instead. |
| auto clientIter = std::find(begin(mActiveClients), end(mActiveClients), client); |
| LOG_ALWAYS_FATAL_IF(clientIter != mActiveClients.end(), |
| "%s(%d) removing client portId %d which is active (count %d)", |
| __func__, mId, portId, client->getActivityCount()); |
| ClientMapHandler<TrackClientDescriptor>::removeClient(portId); |
| } |
| |
| const TrackClientVector& getActiveClients() const { |
| return mActiveClients; |
| } |
| |
| bool useHwGain() const |
| { |
| return !devices().isEmpty() ? devices().itemAt(0)->hasGainController() : false; |
| } |
| |
| DeviceVector mDevices; /**< current devices this output is routed to */ |
| wp<AudioPolicyMix> mPolicyMix; // non NULL when used by a dynamic policy |
| |
| protected: |
| const sp<PolicyAudioPort> mPolicyAudioPort; |
| AudioPolicyClientInterface * const mClientInterface; |
| uint32_t mGlobalActiveCount = 0; // non-client-specific active count |
| audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE; |
| |
| // The ActiveClients shows the clients that contribute to the @VolumeSource counts |
| // and may include upstream clients from a duplicating thread. |
| // Compare with the ClientMap (mClients) which are external AudioTrack clients of the |
| // output descriptor (and do not count internal PatchTracks). |
| TrackClientVector mActiveClients; |
| |
| RoutingActivities mRoutingActivities; /**< track routing activity on this ouput.*/ |
| |
| VolumeActivities mVolumeActivities; /**< track volume activity on this ouput.*/ |
| }; |
| |
| // Audio output driven by a software mixer in audio flinger. |
| class SwAudioOutputDescriptor: public AudioOutputDescriptor |
| { |
| public: |
| SwAudioOutputDescriptor(const sp<IOProfile>& profile, |
| AudioPolicyClientInterface *clientInterface); |
| virtual ~SwAudioOutputDescriptor() {} |
| |
| void dump(String8 *dst) const override; |
| virtual DeviceVector devices() const; |
| void setDevices(const DeviceVector &devices) { mDevices = devices; } |
| bool sharesHwModuleWith(const sp<SwAudioOutputDescriptor>& outputDesc); |
| virtual DeviceVector supportedDevices() const; |
| virtual bool devicesSupportEncodedFormats(const DeviceTypeSet& deviceTypes); |
| virtual bool containsSingleDeviceSupportingEncodedFormats( |
| const sp<DeviceDescriptor>& device) const; |
| virtual uint32_t latency(); |
| virtual bool isDuplicated() const { return (mOutput1 != NULL && mOutput2 != NULL); } |
| virtual bool isFixedVolume(const DeviceTypeSet& deviceTypes); |
| sp<SwAudioOutputDescriptor> subOutput1() { return mOutput1; } |
| sp<SwAudioOutputDescriptor> subOutput2() { return mOutput2; } |
| void setClientActive(const sp<TrackClientDescriptor>& client, bool active) override; |
| void setAllClientsInactive() |
| { |
| for (const auto &client : clientsList(true)) { |
| setClientActive(client, false); |
| } |
| } |
| |
| /** |
| * @brief setSwMute for SwOutput routed on a device that supports Hw Gain, this function allows |
| * to mute the tracks associated to a given volume source only. |
| * As an output may host one or more source(s), and as AudioPolicyManager may dispatch or not |
| * the volume change request according to the priority of the volume source to control the |
| * unique hw gain controller, a separated API allows to force a mute/unmute of a volume source. |
| * @param muted true to mute, false otherwise |
| * @param vs volume source to be considered |
| * @param device scoped for the change |
| * @param delayMs potentially applyed to prevent cut sounds. |
| */ |
| void setSwMute(bool muted, VolumeSource vs, const StreamTypeVector &streams, |
| const DeviceTypeSet& device, uint32_t delayMs); |
| |
| virtual bool setVolume(float volumeDb, bool muted, |
| VolumeSource volumeSource, const StreamTypeVector &streams, |
| const DeviceTypeSet& device, |
| uint32_t delayMs, |
| bool force); |
| |
| virtual void toAudioPortConfig(struct audio_port_config *dstConfig, |
| const struct audio_port_config *srcConfig = NULL) const; |
| virtual void toAudioPort(struct audio_port_v7 *port) const; |
| |
| status_t open(const audio_config_t *config, |
| const DeviceVector &devices, |
| audio_stream_type_t stream, |
| audio_output_flags_t flags, |
| audio_io_handle_t *output); |
| |
| // Called when a stream is about to be started |
| // Note: called before setClientActive(true); |
| status_t start(); |
| // Called after a stream is stopped. |
| // Note: called after setClientActive(false); |
| void stop(); |
| void close(); |
| status_t openDuplicating(const sp<SwAudioOutputDescriptor>& output1, |
| const sp<SwAudioOutputDescriptor>& output2, |
| audio_io_handle_t *ioHandle); |
| |
| /** |
| * @brief supportsDevice |
| * @param device to be checked against |
| * @return true if the device is supported by type (for non bus / remote submix devices), |
| * true if the device is supported (both type and address) for bus / remote submix |
| * false otherwise |
| */ |
| bool supportsDevice(const sp<DeviceDescriptor> &device) const; |
| |
| /** |
| * @brief supportsAllDevices |
| * @param devices to be checked against |
| * @return true if the device is weakly supported by type (e.g. for non bus / rsubmix devices), |
| * true if the device is supported (both type and address) for bus / remote submix |
| * false otherwise |
| */ |
| bool supportsAllDevices(const DeviceVector &devices) const; |
| |
| /** |
| * @brief supportsDevicesForPlayback |
| * @param devices to be checked against |
| * @return true if the devices is a supported combo for playback |
| * false otherwise |
| */ |
| bool supportsDevicesForPlayback(const DeviceVector &devices) const; |
| |
| /** |
| * @brief filterSupportedDevices takes a vector of devices and filters them according to the |
| * device supported by this output (the profile from which this output derives from) |
| * @param devices reference device vector to be filtered |
| * @return vector of devices filtered from the supported devices of this output (weakly or not |
| * depending on the device type) |
| */ |
| DeviceVector filterSupportedDevices(const DeviceVector &devices) const; |
| |
| const sp<IOProfile> mProfile; // I/O profile this output derives from |
| audio_io_handle_t mIoHandle; // output handle |
| uint32_t mLatency; // |
| audio_output_flags_t mFlags; // |
| sp<SwAudioOutputDescriptor> mOutput1; // used by duplicated outputs: first output |
| sp<SwAudioOutputDescriptor> mOutput2; // used by duplicated outputs: second output |
| uint32_t mDirectOpenCount; // number of clients using this output (direct outputs only) |
| audio_session_t mDirectClientSession; // session id of the direct output client |
| bool mPendingReopenToQueryProfiles = false; |
| }; |
| |
| // Audio output driven by an input device directly. |
| class HwAudioOutputDescriptor: public AudioOutputDescriptor |
| { |
| public: |
| HwAudioOutputDescriptor(const sp<SourceClientDescriptor>& source, |
| AudioPolicyClientInterface *clientInterface); |
| virtual ~HwAudioOutputDescriptor() {} |
| |
| void dump(String8 *dst) const override; |
| |
| virtual bool setVolume(float volumeDb, bool muted, |
| VolumeSource volumeSource, const StreamTypeVector &streams, |
| const DeviceTypeSet& deviceTypes, |
| uint32_t delayMs, |
| bool force); |
| |
| virtual void toAudioPortConfig(struct audio_port_config *dstConfig, |
| const struct audio_port_config *srcConfig = NULL) const; |
| virtual void toAudioPort(struct audio_port_v7 *port) const; |
| |
| const sp<SourceClientDescriptor> mSource; |
| |
| }; |
| |
| class SwAudioOutputCollection : |
| public DefaultKeyedVector< audio_io_handle_t, sp<SwAudioOutputDescriptor> > |
| { |
| public: |
| bool isActive(VolumeSource volumeSource, uint32_t inPastMs = 0) const; |
| |
| /** |
| * return whether any source contributing to VolumeSource is playing remotely, override |
| * to change the definition of |
| * local/remote playback, used for instance by notification manager to not make |
| * media players lose audio focus when not playing locally |
| * For the base implementation, "remotely" means playing during screen mirroring which |
| * uses an output for playback with a non-empty, non "0" address. |
| */ |
| bool isActiveRemotely(VolumeSource volumeSource, uint32_t inPastMs = 0) const; |
| |
| /** |
| * return whether any source contributing to VolumeSource is playing, but not on a "remote" |
| * device. |
| * Override to change the definition of a local/remote playback. |
| * Used for instance by policy manager to alter the speaker playback ("speaker safe" behavior) |
| * when media plays or not locally. |
| * For the base implementation, "remotely" means playing during screen mirroring. |
| */ |
| bool isActiveLocally(VolumeSource volumeSource, uint32_t inPastMs = 0) const; |
| |
| /** |
| * @brief isStrategyActiveOnSameModule checks if the given strategy is active (or was active |
| * in the past) on the given output and all the outputs belonging to the same HW Module |
| * the same module than the given output |
| * @param outputDesc to be considered |
| * @param ps product strategy to be checked upon activity status |
| * @param inPastMs if 0, check currently, otherwise, check in the past |
| * @param sysTime shall be set if request is done for the past activity. |
| * @return true if an output following the strategy is active on the same module than desc, |
| * false otherwise |
| */ |
| bool isStrategyActiveOnSameModule(product_strategy_t ps, |
| const sp<SwAudioOutputDescriptor>& desc, |
| uint32_t inPastMs = 0, nsecs_t sysTime = 0) const; |
| |
| /** |
| * @brief clearSessionRoutesForDevice: when a device is disconnected, and if this device has |
| * been chosen as the preferred device by any client, the policy manager shall |
| * prevent from using this device any more by clearing all the session routes involving this |
| * device. |
| * In other words, the preferred device port id of these clients will be resetted to NONE. |
| * @param disconnectedDevice device to be disconnected |
| */ |
| void clearSessionRoutesForDevice(const sp<DeviceDescriptor> &disconnectedDevice); |
| |
| /** |
| * returns the A2DP output handle if it is open or 0 otherwise |
| */ |
| audio_io_handle_t getA2dpOutput() const; |
| |
| /** |
| * returns true if primary HAL supports A2DP Offload |
| */ |
| bool isA2dpOffloadedOnPrimary() const; |
| |
| sp<SwAudioOutputDescriptor> getOutputFromId(audio_port_handle_t id) const; |
| |
| sp<SwAudioOutputDescriptor> getPrimaryOutput() const; |
| |
| /** |
| * @brief isAnyOutputActive checks if any output is active (aka playing) except the one(s) that |
| * hold the volume source to be ignored |
| * @param volumeSourceToIgnore source not to be considered in the activity detection |
| * @return true if any output is active for any volume source except the one to be ignored |
| */ |
| bool isAnyOutputActive(VolumeSource volumeSourceToIgnore) const |
| { |
| for (size_t i = 0; i < size(); i++) { |
| const sp<AudioOutputDescriptor> &outputDesc = valueAt(i); |
| if (outputDesc->isAnyActive(volumeSourceToIgnore)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| audio_devices_t getSupportedDevices(audio_io_handle_t handle) const; |
| |
| sp<SwAudioOutputDescriptor> getOutputForClient(audio_port_handle_t portId); |
| |
| void dump(String8 *dst) const; |
| }; |
| |
| class HwAudioOutputCollection : |
| public DefaultKeyedVector< audio_io_handle_t, sp<HwAudioOutputDescriptor> > |
| { |
| public: |
| bool isActive(VolumeSource volumeSource, uint32_t inPastMs = 0) const; |
| |
| /** |
| * @brief isAnyOutputActive checks if any output is active (aka playing) except the one(s) that |
| * hold the volume source to be ignored |
| * @param volumeSourceToIgnore source not to be considered in the activity detection |
| * @return true if any output is active for any volume source except the one to be ignored |
| */ |
| bool isAnyOutputActive(VolumeSource volumeSourceToIgnore) const |
| { |
| for (size_t i = 0; i < size(); i++) { |
| const sp<AudioOutputDescriptor> &outputDesc = valueAt(i); |
| if (outputDesc->isAnyActive(volumeSourceToIgnore)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| void dump(String8 *dst) const; |
| }; |
| |
| |
| } // namespace android |