Loading media/libaudiofoundation/include/media/DeviceDescriptorBase.h +2 −2 Original line number Diff line number Diff line Loading @@ -79,8 +79,8 @@ public: bool equals(const sp<DeviceDescriptorBase>& other) const; status_t writeToParcelable(media::AudioPortFw* parcelable) const; status_t readFromParcelable(const media::AudioPortFw& parcelable); virtual status_t writeToParcelable(media::AudioPortFw* parcelable) const; virtual status_t readFromParcelable(const media::AudioPortFw& parcelable); protected: AudioDeviceTypeAddr mDeviceTypeAddr; Loading media/libaudiohal/impl/DeviceHalAidl.cpp +152 −25 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #include <media/AidlConversionNdkCpp.h> #include <media/AidlConversionUtil.h> #include <mediautils/TimeCheck.h> #include <system/audio.h> #include <Utils.h> #include <utils/Log.h> Loading @@ -41,6 +42,7 @@ using aidl::android::media::audio::common::AudioChannelLayout; using aidl::android::media::audio::common::AudioConfig; using aidl::android::media::audio::common::AudioDevice; using aidl::android::media::audio::common::AudioDeviceAddress; using aidl::android::media::audio::common::AudioDeviceDescription; using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioFormatDescription; using aidl::android::media::audio::common::AudioFormatType; Loading Loading @@ -185,23 +187,77 @@ status_t DeviceHalAidl::initCheck() { RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports))); ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports", __func__, mInstance.c_str()); std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()), [](const auto& p) { return std::make_pair(p.id, p); }); mDefaultInputPortId = mDefaultOutputPortId = -1; const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE; for (const auto& pair : mPorts) { const auto& p = pair.second; if (p.ext.getTag() == AudioPortExt::Tag::device && (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) { if (p.flags.getTag() == AudioIoFlags::Tag::input) { mDefaultInputPortId = p.id; } else if (p.flags.getTag() == AudioIoFlags::Tag::output) { mDefaultOutputPortId = p.id; for (auto it = ports.begin(); it != ports.end(); ) { const auto& port = *it; if (port.ext.getTag() != AudioPortExt::Tag::device) { ++it; continue; } const AudioPortDeviceExt& deviceExt = port.ext.get<AudioPortExt::Tag::device>(); if ((deviceExt.flags & defaultDeviceFlag) != 0) { if (port.flags.getTag() == AudioIoFlags::Tag::input) { mDefaultInputPortId = port.id; } else if (port.flags.getTag() == AudioIoFlags::Tag::output) { mDefaultOutputPortId = port.id; } } // For compatibility with HIDL, hide "template" remote submix ports from ports list. if (const auto& devDesc = deviceExt.device; (devDesc.type.type == AudioDeviceType::IN_SUBMIX || devDesc.type.type == AudioDeviceType::OUT_SUBMIX) && devDesc.type.connection == AudioDeviceDescription::CONNECTION_VIRTUAL) { if (devDesc.type.type == AudioDeviceType::IN_SUBMIX) { mRemoteSubmixIn = port; } else { mRemoteSubmixOut = port; } it = ports.erase(it); } else { ++it; } } if (mRemoteSubmixIn.has_value() != mRemoteSubmixOut.has_value()) { ALOGE("%s: The configuration only has input or output remote submix device, must have both", __func__); mRemoteSubmixIn.reset(); mRemoteSubmixOut.reset(); } if (mRemoteSubmixIn.has_value()) { AudioPort connectedRSubmixIn = *mRemoteSubmixIn; connectedRSubmixIn.ext.get<AudioPortExt::Tag::device>().device.address = AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS; ALOGD("%s: connecting remote submix input", __func__); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice( connectedRSubmixIn, &connectedRSubmixIn))); // The template port for the remote submix input couldn't be "default" because it is not // attached. The connected port can now be made default because we never disconnect it. if (mDefaultInputPortId == -1) { mDefaultInputPortId = connectedRSubmixIn.id; } ports.push_back(std::move(connectedRSubmixIn)); // Remote submix output must not be connected until the framework actually starts // using it, however for legacy compatibility we need to provide an "augmented template" // port with an address and profiles. It is obtained by connecting the output and then // immediately disconnecting it. This is a cheap operation as we don't open any streams. AudioPort tempConnectedRSubmixOut = *mRemoteSubmixOut; tempConnectedRSubmixOut.ext.get<AudioPortExt::Tag::device>().device.address = AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS; ALOGD("%s: temporarily connecting and disconnecting remote submix output", __func__); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice( tempConnectedRSubmixOut, &tempConnectedRSubmixOut))); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice( tempConnectedRSubmixOut.id))); tempConnectedRSubmixOut.id = mRemoteSubmixOut->id; ports.push_back(std::move(tempConnectedRSubmixOut)); } ALOGI("%s: module %s default port ids: input %d, output %d", __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId); std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()), [](const auto& p) { return std::make_pair(p.id, p); }); RETURN_STATUS_IF_ERROR(updateRoutes()); std::vector<AudioPortConfig> portConfigs; RETURN_STATUS_IF_ERROR( Loading Loading @@ -1079,6 +1135,7 @@ status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_por } status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) { ALOGD("%p %s::%s", this, getClassName().c_str(), __func__); TIME_CHECK(); if (!mModule) return NO_INIT; if (port == nullptr) { Loading @@ -1104,8 +1161,28 @@ status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool } if (connected) { AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device; std::optional<AudioPort> templatePort; auto erasePortAfterConnectionIt = mPorts.end(); // Connection of remote submix out with address "0" is a special case. Since there is // already an "augmented template" port with this address in mPorts, we need to replace // it with a connected port. // Connection of remote submix outs with any other address is done as usual except that // the template port is in `mRemoteSubmixOut`. if (mRemoteSubmixOut.has_value() && matchDevice.type.type == AudioDeviceType::OUT_SUBMIX) { if (matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>( AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) { erasePortAfterConnectionIt = findPort(matchDevice); } templatePort = mRemoteSubmixOut; } else if (mRemoteSubmixIn.has_value() && matchDevice.type.type == AudioDeviceType::IN_SUBMIX) { templatePort = mRemoteSubmixIn; } else { // Reset the device address to find the "template" port. matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(); } if (!templatePort.has_value()) { auto portsIt = findPort(matchDevice); if (portsIt == mPorts.end()) { // Since 'setConnectedState' is called for all modules, it is normal when the device Loading @@ -1115,9 +1192,12 @@ status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool ALOGD("%s: device port for device %s found in the module %s", __func__, matchDevice.toString().c_str(), mInstance.c_str()); } templatePort = portsIt->second; } resetUnusedPatchesAndPortConfigs(); // Use the ID of the "template" port, use all the information from the provided port. aidlPort.id = portsIt->first; aidlPort.id = templatePort->id; AudioPort connectedPort; RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice( aidlPort, &connectedPort))); Loading @@ -1127,6 +1207,9 @@ status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool __func__, mInstance.c_str(), connectedPort.toString().c_str(), it->second.toString().c_str()); mConnectedPorts[connectedPort.id] = false; if (erasePortAfterConnectionIt != mPorts.end()) { mPorts.erase(erasePortAfterConnectionIt); } } else { // !connected AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device; auto portsIt = findPort(matchDevice); Loading @@ -1139,14 +1222,24 @@ status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool __func__, matchDevice.toString().c_str(), mInstance.c_str()); } resetUnusedPatchesAndPortConfigs(); // Disconnection of remote submix out with address "0" is a special case. We need to replace // the connected port entry with the "augmented template". const int32_t portId = portsIt->second.id; if (mRemoteSubmixOut.has_value() && matchDevice.type.type == AudioDeviceType::OUT_SUBMIX && matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>( AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) { mDisconnectedPortReplacement = std::make_pair(portId, *mRemoteSubmixOut); auto& port = mDisconnectedPortReplacement.second; port.ext.get<AudioPortExt::Tag::device>().device = matchDevice; port.profiles = portsIt->second.profiles; } // Streams are closed by AudioFlinger independently from device disconnections. // It is possible that the stream has not been closed yet. const int32_t portId = portsIt->second.id; if (!isPortHeldByAStream(portId)) { RETURN_STATUS_IF_ERROR(statusTFromBinderStatus( mModule->disconnectExternalDevice(portId))); mPorts.erase(portsIt); mConnectedPorts.erase(portId); eraseConnectedPort(portId); } else { ALOGD("%s: since device port ID %d is used by a stream, " "external device disconnection postponed", __func__, portId); Loading Loading @@ -1216,6 +1309,17 @@ status_t DeviceHalAidl::createOrUpdatePortConfig( return OK; } void DeviceHalAidl::eraseConnectedPort(int32_t portId) { mPorts.erase(portId); mConnectedPorts.erase(portId); if (mDisconnectedPortReplacement.first == portId) { const auto& port = mDisconnectedPortReplacement.second; mPorts.insert(std::make_pair(port.id, port)); ALOGD("%s: disconnected port replacement: %s", __func__, port.toString().c_str()); mDisconnectedPortReplacement = std::pair<int32_t, AudioPort>(); } } status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters( AudioParameter &keys, AudioParameter *result) { TIME_CHECK(); Loading Loading @@ -1847,8 +1951,7 @@ void DeviceHalAidl::resetUnusedPortConfigs() { if (!isPortHeldByAStream(portId)) { TIME_CHECK(); if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) { mPorts.erase(portId); mConnectedPorts.erase(portId); eraseConnectedPort(portId); ALOGD("%s: executed postponed external device disconnection for port ID %d", __func__, portId); } Loading @@ -1865,6 +1968,30 @@ status_t DeviceHalAidl::updateRoutes() { statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes))); ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes", __func__, mInstance.c_str()); if (mRemoteSubmixIn.has_value()) { // Remove mentions of the template remote submix input from routes. int32_t rSubmixInId = mRemoteSubmixIn->id; // Remove mentions of the template remote submix out only if it is not in mPorts // (that means there is a connected port in mPorts). int32_t rSubmixOutId = mPorts.find(mRemoteSubmixOut->id) == mPorts.end() ? mRemoteSubmixOut->id : -1; for (auto it = mRoutes.begin(); it != mRoutes.end();) { auto& route = *it; if (route.sinkPortId == rSubmixOutId) { it = mRoutes.erase(it); continue; } if (auto sourceIt = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(), rSubmixInId); sourceIt != route.sourcePortIds.end()) { route.sourcePortIds.erase(sourceIt); if (route.sourcePortIds.empty()) { it = mRoutes.erase(it); continue; } } ++it; } } mRoutingMatrix.clear(); for (const auto& r : mRoutes) { for (auto portId : r.sourcePortIds) { Loading media/libaudiohal/impl/DeviceHalAidl.h +7 −0 Original line number Diff line number Diff line Loading @@ -223,6 +223,7 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl, status_t createOrUpdatePortConfig( const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool *created); void eraseConnectedPort(int32_t portId); status_t filterAndRetrieveBtA2dpParameters(AudioParameter &keys, AudioParameter *result); status_t filterAndUpdateBtA2dpParameters(AudioParameter ¶meters); status_t filterAndUpdateBtHfpParameters(AudioParameter ¶meters); Loading Loading @@ -313,6 +314,10 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl, std::shared_ptr<::aidl::android::hardware::audio::core::sounddose::ISoundDose> mSoundDose = nullptr; Ports mPorts; // Remote submix "template" ports (no address specified, no profiles). // They are excluded from `mPorts` as their presence confuses the framework code. std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixIn; std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixOut; int32_t mDefaultInputPortId = -1; int32_t mDefaultOutputPortId = -1; PortConfigs mPortConfigs; Loading @@ -326,6 +331,8 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl, std::map<void*, Callbacks> mCallbacks GUARDED_BY(mLock); std::set<audio_port_handle_t> mDeviceDisconnectionNotified; ConnectedPorts mConnectedPorts; std::pair<int32_t, ::aidl::android::media::audio::common::AudioPort> mDisconnectedPortReplacement; }; } // namespace android services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h +3 −1 Original line number Diff line number Diff line Loading @@ -89,6 +89,8 @@ public: void importAudioPortAndPickAudioProfile(const sp<PolicyAudioPort>& policyPort, bool force = false); status_t readFromParcelable(const media::AudioPortFw& parcelable) override; void setEncapsulationInfoFromHal(AudioPolicyClientInterface *clientInterface); void dump(String8 *dst, int spaces, bool verbose = true) const; Loading @@ -104,7 +106,7 @@ private: std::string mTagName; // Unique human readable identifier for a device port found in conf file. audio_format_t mCurrentEncodedFormat; bool mIsDynamic = false; const std::string mDeclaredAddress; // Original device address std::string mDeclaredAddress; // Original device address }; class DeviceVector : public SortedVector<sp<DeviceDescriptor> > Loading services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp +9 −2 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ namespace android { using media::audio::common::AudioDeviceAddress; using media::audio::common::AudioDeviceType; using media::audio::common::AudioIoFlags; using media::audio::common::AudioPortDeviceExt; using media::audio::common::AudioPortExt; Loading Loading @@ -113,12 +115,17 @@ status_t aidl2legacy_AudioHwModule_HwModule(const media::AudioHwModule& aidl, ports.emplace(aidlPort.id, devicePort); if (const auto& deviceExt = aidlPort.ext.get<AudioPortExt::device>(); deviceExt.device.type.connection.empty()) { // Attached device deviceExt.device.type.connection.empty() || // DeviceHalAidl connects remote submix input with an address. (deviceExt.device.type.type == AudioDeviceType::IN_SUBMIX && deviceExt.device.address != AudioDeviceAddress())) { // Attached device. if (isInput) { attachedInputDevices->add(devicePort); } else { attachedOutputDevices->add(devicePort); if ((deviceExt.flags & defaultDeviceFlag) != 0) { if (*defaultOutputDevice == nullptr && (deviceExt.flags & defaultDeviceFlag) != 0) { *defaultOutputDevice = devicePort; } } Loading Loading
media/libaudiofoundation/include/media/DeviceDescriptorBase.h +2 −2 Original line number Diff line number Diff line Loading @@ -79,8 +79,8 @@ public: bool equals(const sp<DeviceDescriptorBase>& other) const; status_t writeToParcelable(media::AudioPortFw* parcelable) const; status_t readFromParcelable(const media::AudioPortFw& parcelable); virtual status_t writeToParcelable(media::AudioPortFw* parcelable) const; virtual status_t readFromParcelable(const media::AudioPortFw& parcelable); protected: AudioDeviceTypeAddr mDeviceTypeAddr; Loading
media/libaudiohal/impl/DeviceHalAidl.cpp +152 −25 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ #include <media/AidlConversionNdkCpp.h> #include <media/AidlConversionUtil.h> #include <mediautils/TimeCheck.h> #include <system/audio.h> #include <Utils.h> #include <utils/Log.h> Loading @@ -41,6 +42,7 @@ using aidl::android::media::audio::common::AudioChannelLayout; using aidl::android::media::audio::common::AudioConfig; using aidl::android::media::audio::common::AudioDevice; using aidl::android::media::audio::common::AudioDeviceAddress; using aidl::android::media::audio::common::AudioDeviceDescription; using aidl::android::media::audio::common::AudioDeviceType; using aidl::android::media::audio::common::AudioFormatDescription; using aidl::android::media::audio::common::AudioFormatType; Loading Loading @@ -185,23 +187,77 @@ status_t DeviceHalAidl::initCheck() { RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->getAudioPorts(&ports))); ALOGW_IF(ports.empty(), "%s: module %s returned an empty list of audio ports", __func__, mInstance.c_str()); std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()), [](const auto& p) { return std::make_pair(p.id, p); }); mDefaultInputPortId = mDefaultOutputPortId = -1; const int defaultDeviceFlag = 1 << AudioPortDeviceExt::FLAG_INDEX_DEFAULT_DEVICE; for (const auto& pair : mPorts) { const auto& p = pair.second; if (p.ext.getTag() == AudioPortExt::Tag::device && (p.ext.get<AudioPortExt::Tag::device>().flags & defaultDeviceFlag) != 0) { if (p.flags.getTag() == AudioIoFlags::Tag::input) { mDefaultInputPortId = p.id; } else if (p.flags.getTag() == AudioIoFlags::Tag::output) { mDefaultOutputPortId = p.id; for (auto it = ports.begin(); it != ports.end(); ) { const auto& port = *it; if (port.ext.getTag() != AudioPortExt::Tag::device) { ++it; continue; } const AudioPortDeviceExt& deviceExt = port.ext.get<AudioPortExt::Tag::device>(); if ((deviceExt.flags & defaultDeviceFlag) != 0) { if (port.flags.getTag() == AudioIoFlags::Tag::input) { mDefaultInputPortId = port.id; } else if (port.flags.getTag() == AudioIoFlags::Tag::output) { mDefaultOutputPortId = port.id; } } // For compatibility with HIDL, hide "template" remote submix ports from ports list. if (const auto& devDesc = deviceExt.device; (devDesc.type.type == AudioDeviceType::IN_SUBMIX || devDesc.type.type == AudioDeviceType::OUT_SUBMIX) && devDesc.type.connection == AudioDeviceDescription::CONNECTION_VIRTUAL) { if (devDesc.type.type == AudioDeviceType::IN_SUBMIX) { mRemoteSubmixIn = port; } else { mRemoteSubmixOut = port; } it = ports.erase(it); } else { ++it; } } if (mRemoteSubmixIn.has_value() != mRemoteSubmixOut.has_value()) { ALOGE("%s: The configuration only has input or output remote submix device, must have both", __func__); mRemoteSubmixIn.reset(); mRemoteSubmixOut.reset(); } if (mRemoteSubmixIn.has_value()) { AudioPort connectedRSubmixIn = *mRemoteSubmixIn; connectedRSubmixIn.ext.get<AudioPortExt::Tag::device>().device.address = AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS; ALOGD("%s: connecting remote submix input", __func__); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice( connectedRSubmixIn, &connectedRSubmixIn))); // The template port for the remote submix input couldn't be "default" because it is not // attached. The connected port can now be made default because we never disconnect it. if (mDefaultInputPortId == -1) { mDefaultInputPortId = connectedRSubmixIn.id; } ports.push_back(std::move(connectedRSubmixIn)); // Remote submix output must not be connected until the framework actually starts // using it, however for legacy compatibility we need to provide an "augmented template" // port with an address and profiles. It is obtained by connecting the output and then // immediately disconnecting it. This is a cheap operation as we don't open any streams. AudioPort tempConnectedRSubmixOut = *mRemoteSubmixOut; tempConnectedRSubmixOut.ext.get<AudioPortExt::Tag::device>().device.address = AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS; ALOGD("%s: temporarily connecting and disconnecting remote submix output", __func__); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice( tempConnectedRSubmixOut, &tempConnectedRSubmixOut))); RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->disconnectExternalDevice( tempConnectedRSubmixOut.id))); tempConnectedRSubmixOut.id = mRemoteSubmixOut->id; ports.push_back(std::move(tempConnectedRSubmixOut)); } ALOGI("%s: module %s default port ids: input %d, output %d", __func__, mInstance.c_str(), mDefaultInputPortId, mDefaultOutputPortId); std::transform(ports.begin(), ports.end(), std::inserter(mPorts, mPorts.end()), [](const auto& p) { return std::make_pair(p.id, p); }); RETURN_STATUS_IF_ERROR(updateRoutes()); std::vector<AudioPortConfig> portConfigs; RETURN_STATUS_IF_ERROR( Loading Loading @@ -1079,6 +1135,7 @@ status_t DeviceHalAidl::prepareToDisconnectExternalDevice(const struct audio_por } status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool connected) { ALOGD("%p %s::%s", this, getClassName().c_str(), __func__); TIME_CHECK(); if (!mModule) return NO_INIT; if (port == nullptr) { Loading @@ -1104,8 +1161,28 @@ status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool } if (connected) { AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device; std::optional<AudioPort> templatePort; auto erasePortAfterConnectionIt = mPorts.end(); // Connection of remote submix out with address "0" is a special case. Since there is // already an "augmented template" port with this address in mPorts, we need to replace // it with a connected port. // Connection of remote submix outs with any other address is done as usual except that // the template port is in `mRemoteSubmixOut`. if (mRemoteSubmixOut.has_value() && matchDevice.type.type == AudioDeviceType::OUT_SUBMIX) { if (matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>( AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) { erasePortAfterConnectionIt = findPort(matchDevice); } templatePort = mRemoteSubmixOut; } else if (mRemoteSubmixIn.has_value() && matchDevice.type.type == AudioDeviceType::IN_SUBMIX) { templatePort = mRemoteSubmixIn; } else { // Reset the device address to find the "template" port. matchDevice.address = AudioDeviceAddress::make<AudioDeviceAddress::id>(); } if (!templatePort.has_value()) { auto portsIt = findPort(matchDevice); if (portsIt == mPorts.end()) { // Since 'setConnectedState' is called for all modules, it is normal when the device Loading @@ -1115,9 +1192,12 @@ status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool ALOGD("%s: device port for device %s found in the module %s", __func__, matchDevice.toString().c_str(), mInstance.c_str()); } templatePort = portsIt->second; } resetUnusedPatchesAndPortConfigs(); // Use the ID of the "template" port, use all the information from the provided port. aidlPort.id = portsIt->first; aidlPort.id = templatePort->id; AudioPort connectedPort; RETURN_STATUS_IF_ERROR(statusTFromBinderStatus(mModule->connectExternalDevice( aidlPort, &connectedPort))); Loading @@ -1127,6 +1207,9 @@ status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool __func__, mInstance.c_str(), connectedPort.toString().c_str(), it->second.toString().c_str()); mConnectedPorts[connectedPort.id] = false; if (erasePortAfterConnectionIt != mPorts.end()) { mPorts.erase(erasePortAfterConnectionIt); } } else { // !connected AudioDevice matchDevice = aidlPort.ext.get<AudioPortExt::device>().device; auto portsIt = findPort(matchDevice); Loading @@ -1139,14 +1222,24 @@ status_t DeviceHalAidl::setConnectedState(const struct audio_port_v7 *port, bool __func__, matchDevice.toString().c_str(), mInstance.c_str()); } resetUnusedPatchesAndPortConfigs(); // Disconnection of remote submix out with address "0" is a special case. We need to replace // the connected port entry with the "augmented template". const int32_t portId = portsIt->second.id; if (mRemoteSubmixOut.has_value() && matchDevice.type.type == AudioDeviceType::OUT_SUBMIX && matchDevice.address == AudioDeviceAddress::make<AudioDeviceAddress::id>( AUDIO_REMOTE_SUBMIX_DEVICE_ADDRESS)) { mDisconnectedPortReplacement = std::make_pair(portId, *mRemoteSubmixOut); auto& port = mDisconnectedPortReplacement.second; port.ext.get<AudioPortExt::Tag::device>().device = matchDevice; port.profiles = portsIt->second.profiles; } // Streams are closed by AudioFlinger independently from device disconnections. // It is possible that the stream has not been closed yet. const int32_t portId = portsIt->second.id; if (!isPortHeldByAStream(portId)) { RETURN_STATUS_IF_ERROR(statusTFromBinderStatus( mModule->disconnectExternalDevice(portId))); mPorts.erase(portsIt); mConnectedPorts.erase(portId); eraseConnectedPort(portId); } else { ALOGD("%s: since device port ID %d is used by a stream, " "external device disconnection postponed", __func__, portId); Loading Loading @@ -1216,6 +1309,17 @@ status_t DeviceHalAidl::createOrUpdatePortConfig( return OK; } void DeviceHalAidl::eraseConnectedPort(int32_t portId) { mPorts.erase(portId); mConnectedPorts.erase(portId); if (mDisconnectedPortReplacement.first == portId) { const auto& port = mDisconnectedPortReplacement.second; mPorts.insert(std::make_pair(port.id, port)); ALOGD("%s: disconnected port replacement: %s", __func__, port.toString().c_str()); mDisconnectedPortReplacement = std::pair<int32_t, AudioPort>(); } } status_t DeviceHalAidl::filterAndRetrieveBtA2dpParameters( AudioParameter &keys, AudioParameter *result) { TIME_CHECK(); Loading Loading @@ -1847,8 +1951,7 @@ void DeviceHalAidl::resetUnusedPortConfigs() { if (!isPortHeldByAStream(portId)) { TIME_CHECK(); if (auto status = mModule->disconnectExternalDevice(portId); status.isOk()) { mPorts.erase(portId); mConnectedPorts.erase(portId); eraseConnectedPort(portId); ALOGD("%s: executed postponed external device disconnection for port ID %d", __func__, portId); } Loading @@ -1865,6 +1968,30 @@ status_t DeviceHalAidl::updateRoutes() { statusTFromBinderStatus(mModule->getAudioRoutes(&mRoutes))); ALOGW_IF(mRoutes.empty(), "%s: module %s returned an empty list of audio routes", __func__, mInstance.c_str()); if (mRemoteSubmixIn.has_value()) { // Remove mentions of the template remote submix input from routes. int32_t rSubmixInId = mRemoteSubmixIn->id; // Remove mentions of the template remote submix out only if it is not in mPorts // (that means there is a connected port in mPorts). int32_t rSubmixOutId = mPorts.find(mRemoteSubmixOut->id) == mPorts.end() ? mRemoteSubmixOut->id : -1; for (auto it = mRoutes.begin(); it != mRoutes.end();) { auto& route = *it; if (route.sinkPortId == rSubmixOutId) { it = mRoutes.erase(it); continue; } if (auto sourceIt = std::find(route.sourcePortIds.begin(), route.sourcePortIds.end(), rSubmixInId); sourceIt != route.sourcePortIds.end()) { route.sourcePortIds.erase(sourceIt); if (route.sourcePortIds.empty()) { it = mRoutes.erase(it); continue; } } ++it; } } mRoutingMatrix.clear(); for (const auto& r : mRoutes) { for (auto portId : r.sourcePortIds) { Loading
media/libaudiohal/impl/DeviceHalAidl.h +7 −0 Original line number Diff line number Diff line Loading @@ -223,6 +223,7 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl, status_t createOrUpdatePortConfig( const ::aidl::android::media::audio::common::AudioPortConfig& requestedPortConfig, PortConfigs::iterator* result, bool *created); void eraseConnectedPort(int32_t portId); status_t filterAndRetrieveBtA2dpParameters(AudioParameter &keys, AudioParameter *result); status_t filterAndUpdateBtA2dpParameters(AudioParameter ¶meters); status_t filterAndUpdateBtHfpParameters(AudioParameter ¶meters); Loading Loading @@ -313,6 +314,10 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl, std::shared_ptr<::aidl::android::hardware::audio::core::sounddose::ISoundDose> mSoundDose = nullptr; Ports mPorts; // Remote submix "template" ports (no address specified, no profiles). // They are excluded from `mPorts` as their presence confuses the framework code. std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixIn; std::optional<::aidl::android::media::audio::common::AudioPort> mRemoteSubmixOut; int32_t mDefaultInputPortId = -1; int32_t mDefaultOutputPortId = -1; PortConfigs mPortConfigs; Loading @@ -326,6 +331,8 @@ class DeviceHalAidl : public DeviceHalInterface, public ConversionHelperAidl, std::map<void*, Callbacks> mCallbacks GUARDED_BY(mLock); std::set<audio_port_handle_t> mDeviceDisconnectionNotified; ConnectedPorts mConnectedPorts; std::pair<int32_t, ::aidl::android::media::audio::common::AudioPort> mDisconnectedPortReplacement; }; } // namespace android
services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h +3 −1 Original line number Diff line number Diff line Loading @@ -89,6 +89,8 @@ public: void importAudioPortAndPickAudioProfile(const sp<PolicyAudioPort>& policyPort, bool force = false); status_t readFromParcelable(const media::AudioPortFw& parcelable) override; void setEncapsulationInfoFromHal(AudioPolicyClientInterface *clientInterface); void dump(String8 *dst, int spaces, bool verbose = true) const; Loading @@ -104,7 +106,7 @@ private: std::string mTagName; // Unique human readable identifier for a device port found in conf file. audio_format_t mCurrentEncodedFormat; bool mIsDynamic = false; const std::string mDeclaredAddress; // Original device address std::string mDeclaredAddress; // Original device address }; class DeviceVector : public SortedVector<sp<DeviceDescriptor> > Loading
services/audiopolicy/common/managerdefinitions/src/AudioPolicyConfig.cpp +9 −2 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ namespace android { using media::audio::common::AudioDeviceAddress; using media::audio::common::AudioDeviceType; using media::audio::common::AudioIoFlags; using media::audio::common::AudioPortDeviceExt; using media::audio::common::AudioPortExt; Loading Loading @@ -113,12 +115,17 @@ status_t aidl2legacy_AudioHwModule_HwModule(const media::AudioHwModule& aidl, ports.emplace(aidlPort.id, devicePort); if (const auto& deviceExt = aidlPort.ext.get<AudioPortExt::device>(); deviceExt.device.type.connection.empty()) { // Attached device deviceExt.device.type.connection.empty() || // DeviceHalAidl connects remote submix input with an address. (deviceExt.device.type.type == AudioDeviceType::IN_SUBMIX && deviceExt.device.address != AudioDeviceAddress())) { // Attached device. if (isInput) { attachedInputDevices->add(devicePort); } else { attachedOutputDevices->add(devicePort); if ((deviceExt.flags & defaultDeviceFlag) != 0) { if (*defaultOutputDevice == nullptr && (deviceExt.flags & defaultDeviceFlag) != 0) { *defaultOutputDevice = devicePort; } } Loading