1 /* 2 * Copyright (C) 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #pragma once 18 19 #include <memory> 20 #include <map> 21 #include <set> 22 #include <utility> 23 #include <vector> 24 25 #include <aidl/android/hardware/audio/core/IModule.h> 26 #include <media/AidlConversionUtil.h> 27 28 #include "Cleanups.h" 29 #include "ConversionHelperAidl.h" 30 31 namespace android { 32 33 class Hal2AidlMapper; 34 class StreamHalInterface; 35 36 // The mapper class is needed because the framework was not yet updated to operate on AIDL-based 37 // structures directly. Mapper does the job of translating the "legacy" way of identifying ports 38 // and port configs (by device addresses and I/O handles) into AIDL IDs. Once the framework will 39 // be updated to provide these IDs directly to libaudiohal, the need for the mapper will cease. 40 // 41 // Note that unlike DeviceHalInterface, which sometimes allows a method to return an error, 42 // but still consider some of the outputs to be valid (for example, in 'open{Input|Output}Stream'), 43 // 'Hal2AidlMapper' follows the Binder convention. It means that if a method returns an error, 44 // the outputs may not be initialized at all and should not be considered by the caller. 45 class Hal2AidlMapper : public ConversionHelperAidl { 46 public: 47 using Cleanups = Cleanups<Hal2AidlMapper>; 48 49 Hal2AidlMapper( 50 const std::string& instance, 51 const std::shared_ptr<::aidl::android::hardware::audio::core::IModule>& module); 52 53 void addStream(const sp<StreamHalInterface>& stream, int32_t mixPortConfigId, int32_t patchId); 54 status_t createOrUpdatePatch( 55 const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sources, 56 const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sinks, 57 int32_t* patchId, Cleanups* cleanups); 58 status_t findPortConfig( 59 const ::aidl::android::media::audio::common::AudioDevice& device, 60 ::aidl::android::media::audio::common::AudioPortConfig* portConfig); 61 status_t getAudioMixPort( 62 int32_t ioHandle, ::aidl::android::media::audio::common::AudioPort* port); 63 status_t getAudioPortCached( 64 const ::aidl::android::media::audio::common::AudioDevice& device, 65 ::aidl::android::media::audio::common::AudioPort* port); 66 template<typename OutputContainer, typename Func> getAudioPorts(OutputContainer * ports,Func converter)67 status_t getAudioPorts(OutputContainer* ports, Func converter) { 68 return ::aidl::android::convertContainer(mPorts, ports, 69 [&converter](const auto& pair) { return converter(pair.second); }); 70 } 71 template<typename OutputContainer, typename Func> getAudioRoutes(OutputContainer * routes,Func converter)72 status_t getAudioRoutes(OutputContainer* routes, Func converter) { 73 return ::aidl::android::convertContainer(mRoutes, routes, converter); 74 } 75 status_t initialize(); 76 status_t prepareToDisconnectExternalDevice( 77 const ::aidl::android::media::audio::common::AudioPort& devicePort); 78 // If the resulting 'mixPortConfig->id' is 0, that means the stream was not created, 79 // and 'config' is a suggested config. 80 status_t prepareToOpenStream( 81 int32_t ioHandle, 82 const ::aidl::android::media::audio::common::AudioDevice& device, 83 const ::aidl::android::media::audio::common::AudioIoFlags& flags, 84 ::aidl::android::media::audio::common::AudioSource source, 85 Cleanups* cleanups, 86 ::aidl::android::media::audio::common::AudioConfig* config, 87 ::aidl::android::media::audio::common::AudioPortConfig* mixPortConfig, 88 ::aidl::android::hardware::audio::core::AudioPatch* patch); 89 status_t setPortConfig( 90 const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig, 91 const std::set<int32_t>& destinationPortIds, 92 ::aidl::android::media::audio::common::AudioPortConfig* portConfig, 93 Cleanups* cleanups = nullptr); 94 status_t releaseAudioPatch(int32_t patchId); 95 void resetUnusedPatchesAndPortConfigs(); 96 status_t setDevicePortConnectedState( 97 const ::aidl::android::media::audio::common::AudioPort& devicePort, bool connected); 98 99 // Methods to work with FwkPatches. eraseFwkPatch(int32_t fwkPatchId)100 void eraseFwkPatch(int32_t fwkPatchId) { mFwkPatches.erase(fwkPatchId); } findFwkPatch(int32_t fwkPatchId)101 int32_t findFwkPatch(int32_t fwkPatchId) { 102 const auto it = mFwkPatches.find(fwkPatchId); 103 return it != mFwkPatches.end() ? it->second : 0; 104 } updateFwkPatch(int32_t fwkPatchId,int32_t halPatchId)105 void updateFwkPatch(int32_t fwkPatchId, int32_t halPatchId) { 106 mFwkPatches[fwkPatchId] = halPatchId; 107 } 108 109 private: 110 // 'FwkPatches' is used to store patches that diverge from the framework's state. 111 // Uses framework patch ID (aka audio_patch_handle_t) values for indexing. 112 // When the 'key == value', that means Hal2AidlMapper has removed this patch, and it is absent 113 // from 'mPatches', but it still "exists" for the framework. It will either remove it or 114 // re-patch. If the framework re-patches, it will continue to use the same patch handle, 115 // but the HAL will use the new one (since the old patch was reset), thus 'key != value' 116 // for such patches. Since they "exist" both for the framework and the HAL, 'mPatches' 117 // contains their data under HAL patch ID ('value' of 'FwkPatches'). 118 // To avoid confusion, all patchIDs used by Hal2AidlMapper are HAL IDs. Mapping between 119 // framework patch IDs and HAL patch IDs is done by DeviceHalAidl. 120 using FwkPatches = std::map<int32_t /*audio_patch_handle_t*/, int32_t /*patch ID*/>; 121 using Patches = std::map<int32_t /*patch ID*/, 122 ::aidl::android::hardware::audio::core::AudioPatch>; 123 using PortConfigs = std::map<int32_t /*port config ID*/, 124 ::aidl::android::media::audio::common::AudioPortConfig>; 125 using Ports = std::map<int32_t /*port ID*/, ::aidl::android::media::audio::common::AudioPort>; 126 using Routes = std::vector<::aidl::android::hardware::audio::core::AudioRoute>; 127 // Answers the question "whether portID 'first' is reachable from portID 'second'?" 128 // It's not a map because both portIDs are known. The matrix is symmetric. 129 using RoutingMatrix = std::set<std::pair<int32_t, int32_t>>; 130 // There is always a mix port config ID set. The patch ID is set after stream 131 // creation, and can be set to '-1' later if the framework happens to create 132 // a patch between the same endpoints. In that case, the ownership of the patch 133 // is on the framework. 134 using Streams = std::map<wp<StreamHalInterface>, 135 std::pair<int32_t /*mix port config ID*/, int32_t /*patch ID*/>>; 136 137 enum PatchMatch { MATCH_SOURCES, MATCH_SINKS, MATCH_BOTH }; 138 139 const std::shared_ptr<::aidl::android::hardware::audio::core::IModule> mModule; 140 141 bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device, 142 const ::aidl::android::media::audio::common::AudioPort& p); 143 bool audioDeviceMatches(const ::aidl::android::media::audio::common::AudioDevice& device, 144 const ::aidl::android::media::audio::common::AudioPortConfig& p); 145 // If the 'result->id' is 0, that means, the config was not created/updated, 146 // and the 'result' is a suggestion from the HAL. 147 status_t createOrUpdatePortConfig( 148 const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig, 149 ::aidl::android::media::audio::common::AudioPortConfig* result, bool *created); 150 status_t createOrUpdatePortConfigRetry( 151 const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig, 152 ::aidl::android::media::audio::common::AudioPortConfig* result, bool *created); 153 void eraseConnectedPort(int32_t portId); 154 status_t findOrCreatePatch( 155 const std::set<int32_t>& sourcePortConfigIds, 156 const std::set<int32_t>& sinkPortConfigIds, 157 PatchMatch match, 158 ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created); 159 status_t findOrCreatePatch( 160 const ::aidl::android::hardware::audio::core::AudioPatch& requestedPatch, 161 PatchMatch match, 162 ::aidl::android::hardware::audio::core::AudioPatch* patch, bool* created); 163 status_t findOrCreateDevicePortConfig( 164 const ::aidl::android::media::audio::common::AudioDevice& device, 165 const ::aidl::android::media::audio::common::AudioConfig* config, 166 const ::aidl::android::media::audio::common::AudioGainConfig* gainConfig, 167 ::aidl::android::media::audio::common::AudioPortConfig* portConfig, 168 bool* created); 169 // If the resulting 'portConfig->id' is 0, that means the config was not created, 170 // and 'portConfig' is a suggested config. 171 status_t findOrCreateMixPortConfig( 172 const ::aidl::android::media::audio::common::AudioConfig& config, 173 const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags, 174 int32_t ioHandle, 175 ::aidl::android::media::audio::common::AudioSource source, 176 const std::set<int32_t>& destinationPortIds, 177 ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created); 178 status_t findOrCreatePortConfig( 179 const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig, 180 const std::set<int32_t>& destinationPortIds, 181 ::aidl::android::media::audio::common::AudioPortConfig* portConfig, bool* created); 182 Patches::iterator findPatch(const std::set<int32_t>& sourcePortConfigIds, 183 const std::set<int32_t>& sinkPortConfigIds, PatchMatch match); 184 Ports::iterator findPort(const ::aidl::android::media::audio::common::AudioDevice& device); 185 Ports::iterator findPort( 186 const ::aidl::android::media::audio::common::AudioConfig& config, 187 const ::aidl::android::media::audio::common::AudioIoFlags& flags, 188 const std::set<int32_t>& destinationPortIds); 189 PortConfigs::iterator findPortConfig( 190 const ::aidl::android::media::audio::common::AudioDevice& device); 191 PortConfigs::iterator findPortConfig( 192 const std::optional<::aidl::android::media::audio::common::AudioConfig>& config, 193 const std::optional<::aidl::android::media::audio::common::AudioIoFlags>& flags, 194 int32_t ioHandle); 195 std::set<int32_t> getPatchIdsByPortId(int32_t portId); 196 status_t prepareToOpenStreamHelper( 197 int32_t ioHandle, int32_t devicePortId, int32_t devicePortConfigId, 198 const ::aidl::android::media::audio::common::AudioIoFlags& flags, 199 ::aidl::android::media::audio::common::AudioSource source, 200 const ::aidl::android::media::audio::common::AudioConfig& initialConfig, 201 Cleanups* cleanups, ::aidl::android::media::audio::common::AudioConfig* config, 202 ::aidl::android::media::audio::common::AudioPortConfig* mixPortConfig, 203 ::aidl::android::hardware::audio::core::AudioPatch* patch); portConfigBelongsToPort(int32_t portConfigId,int32_t portId)204 bool portConfigBelongsToPort(int32_t portConfigId, int32_t portId) { 205 auto it = mPortConfigs.find(portConfigId); 206 return it != mPortConfigs.end() && it->second.portId == portId; 207 } 208 status_t releaseAudioPatch(Patches::iterator it); 209 status_t releaseAudioPatches(const std::set<int32_t>& patchIds); resetPatch(int32_t patchId)210 void resetPatch(int32_t patchId) { (void)releaseAudioPatch(patchId); } 211 void resetPortConfig(int32_t portConfigId); 212 void resetUnusedPortConfigs(); 213 status_t updateAudioPort( 214 int32_t portId, ::aidl::android::media::audio::common::AudioPort* port); 215 status_t updateRoutes(); 216 void updateDynamicMixPorts(); 217 218 Ports mPorts; 219 // Remote submix "template" ports (no address specified, no profiles). 220 // They are excluded from `mPorts` as their presence confuses the framework code. 221 std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixIn; 222 std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixOut; 223 int32_t mDefaultInputPortId = -1; 224 int32_t mDefaultOutputPortId = -1; 225 FwkPatches mFwkPatches; 226 PortConfigs mPortConfigs; 227 std::set<int32_t> mInitialPortConfigIds; 228 Patches mPatches; 229 Routes mRoutes; 230 RoutingMatrix mRoutingMatrix; 231 Streams mStreams; 232 std::set<int32_t> mConnectedPorts; 233 std::pair<int32_t, ::aidl::android::media::audio::common::AudioPort> 234 mDisconnectedPortReplacement; 235 std::set<int32_t> mDynamicMixPortIds; 236 }; 237 238 } // namespace android 239