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 30 namespace android { 31 32 class Hal2AidlMapper; 33 class StreamHalInterface; 34 35 // The mapper class is needed because the framework was not yet updated to operate on AIDL-based 36 // structures directly. Mapper does the job of translating the "legacy" way of identifying ports 37 // and port configs (by device addresses and I/O handles) into AIDL IDs. Once the framework will 38 // be updated to provide these IDs directly to libaudiohal, the need for the mapper will cease. 39 // 40 // Note that unlike DeviceHalInterface, which sometimes allows a method to return an error, 41 // but still consider some of the outputs to be valid (for example, in 'open{Input|Output}Stream'), 42 // 'Hal2AidlMapper' follows the Binder convention. It means that if a method returns an error, 43 // the outputs may not be initialized at all and should not be considered by the caller. 44 class Hal2AidlMapper { 45 public: 46 using Cleanups = Cleanups<Hal2AidlMapper>; 47 48 Hal2AidlMapper( 49 const std::string& instance, 50 const std::shared_ptr<::aidl::android::hardware::audio::core::IModule>& module); 51 52 void addStream(const sp<StreamHalInterface>& stream, int32_t mixPortConfigId, int32_t patchId); 53 status_t createOrUpdatePatch( 54 const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sources, 55 const std::vector<::aidl::android::media::audio::common::AudioPortConfig>& sinks, 56 int32_t* patchId, Cleanups* cleanups); 57 status_t findPortConfig( 58 const ::aidl::android::media::audio::common::AudioDevice& device, 59 ::aidl::android::media::audio::common::AudioPortConfig* portConfig); 60 status_t getAudioMixPort( 61 int32_t ioHandle, ::aidl::android::media::audio::common::AudioPort* port); 62 status_t getAudioPortCached( 63 const ::aidl::android::media::audio::common::AudioDevice& device, 64 ::aidl::android::media::audio::common::AudioPort* port); 65 template<typename OutputContainer, typename Func> getAudioPorts(OutputContainer * ports,Func converter)66 status_t getAudioPorts(OutputContainer* ports, Func converter) { 67 return ::aidl::android::convertContainer(mPorts, ports, 68 [&converter](const auto& pair) { return converter(pair.second); }); 69 } 70 template<typename OutputContainer, typename Func> getAudioRoutes(OutputContainer * routes,Func converter)71 status_t getAudioRoutes(OutputContainer* routes, Func converter) { 72 return ::aidl::android::convertContainer(mRoutes, routes, converter); 73 } 74 status_t initialize(); 75 status_t prepareToDisconnectExternalDevice( 76 const ::aidl::android::media::audio::common::AudioPort& devicePort); 77 // If the resulting 'mixPortConfig->id' is 0, that means the stream was not created, 78 // and 'config' is a suggested config. 79 status_t prepareToOpenStream( 80 int32_t ioHandle, 81 const ::aidl::android::media::audio::common::AudioDevice& device, 82 const ::aidl::android::media::audio::common::AudioIoFlags& flags, 83 ::aidl::android::media::audio::common::AudioSource source, 84 Cleanups* cleanups, 85 ::aidl::android::media::audio::common::AudioConfig* config, 86 ::aidl::android::media::audio::common::AudioPortConfig* mixPortConfig, 87 ::aidl::android::hardware::audio::core::AudioPatch* patch); 88 status_t setPortConfig( 89 const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig, 90 const std::set<int32_t>& destinationPortIds, 91 ::aidl::android::media::audio::common::AudioPortConfig* portConfig, 92 Cleanups* cleanups = nullptr); 93 status_t releaseAudioPatch(int32_t patchId); 94 void resetUnusedPatchesAndPortConfigs(); 95 status_t setDevicePortConnectedState( 96 const ::aidl::android::media::audio::common::AudioPort& devicePort, bool connected); 97 98 // Methods to work with FwkPatches. eraseFwkPatch(int32_t fwkPatchId)99 void eraseFwkPatch(int32_t fwkPatchId) { mFwkPatches.erase(fwkPatchId); } findFwkPatch(int32_t fwkPatchId)100 int32_t findFwkPatch(int32_t fwkPatchId) { 101 const auto it = mFwkPatches.find(fwkPatchId); 102 return it != mFwkPatches.end() ? it->second : 0; 103 } updateFwkPatch(int32_t fwkPatchId,int32_t halPatchId)104 void updateFwkPatch(int32_t fwkPatchId, int32_t halPatchId) { 105 mFwkPatches[fwkPatchId] = halPatchId; 106 } 107 108 private: 109 // 'FwkPatches' is used to store patches that diverge from the framework's state. 110 // Uses framework patch ID (aka audio_patch_handle_t) values for indexing. 111 // When the 'key == value', that means Hal2AidlMapper has removed this patch, and it is absent 112 // from 'mPatches', but it still "exists" for the framework. It will either remove it or 113 // re-patch. If the framework re-patches, it will continue to use the same patch handle, 114 // but the HAL will use the new one (since the old patch was reset), thus 'key != value' 115 // for such patches. Since they "exist" both for the framework and the HAL, 'mPatches' 116 // contains their data under HAL patch ID ('value' of 'FwkPatches'). 117 // To avoid confusion, all patchIDs used by Hal2AidlMapper are HAL IDs. Mapping between 118 // framework patch IDs and HAL patch IDs is done by DeviceHalAidl. 119 using FwkPatches = std::map<int32_t /*audio_patch_handle_t*/, int32_t /*patch ID*/>; 120 using Patches = std::map<int32_t /*patch ID*/, 121 ::aidl::android::hardware::audio::core::AudioPatch>; 122 using PortConfigs = std::map<int32_t /*port config ID*/, 123 ::aidl::android::media::audio::common::AudioPortConfig>; 124 using Ports = std::map<int32_t /*port ID*/, ::aidl::android::media::audio::common::AudioPort>; 125 using Routes = std::vector<::aidl::android::hardware::audio::core::AudioRoute>; 126 // Answers the question "whether portID 'first' is reachable from portID 'second'?" 127 // It's not a map because both portIDs are known. The matrix is symmetric. 128 using RoutingMatrix = std::set<std::pair<int32_t, int32_t>>; 129 // There is always a mix port config ID set. The patch ID is set after stream 130 // creation, and can be set to '-1' later if the framework happens to create 131 // a patch between the same endpoints. In that case, the ownership of the patch 132 // is on the framework. 133 using Streams = std::map<wp<StreamHalInterface>, 134 std::pair<int32_t /*mix port config ID*/, int32_t /*patch ID*/>>; 135 136 enum PatchMatch { MATCH_SOURCES, MATCH_SINKS, MATCH_BOTH }; 137 138 const std::string mInstance; 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