From 43da7d33f3bcef546c59db33a808ec8a66f4d4cc Mon Sep 17 00:00:00 2001 From: wAABBsif Date: Tue, 20 Jan 2026 23:09:32 -0500 Subject: [PATCH] Implement music attenuation for Linux --- UnleashedRecomp/os/linux/media_linux.cpp | 183 ++++++++++++++++++++++- 1 file changed, 182 insertions(+), 1 deletion(-) diff --git a/UnleashedRecomp/os/linux/media_linux.cpp b/UnleashedRecomp/os/linux/media_linux.cpp index 3bb41076..53bd2d54 100644 --- a/UnleashedRecomp/os/linux/media_linux.cpp +++ b/UnleashedRecomp/os/linux/media_linux.cpp @@ -2,7 +2,188 @@ #include #include +static DBusConnection* CreateDBusConnection() +{ + DBusError dbusError; + dbus_error_init(&dbusError); + + DBusConnection* result = dbus_bus_get(DBUS_BUS_SESSION, &dbusError); + if (dbus_error_is_set(&dbusError)) + { + LOGF_ERROR("Failed to create DBus connection: {0}", dbusError.name); + return nullptr; + } + + return result; +} + +static void DestroyDBusConnection(DBusConnection* connection) +{ + assert(connection != nullptr); + dbus_connection_unref(connection); +} + +static std::vector GetMediaPlayerBusNames(DBusConnection* connection) +{ + assert(connection != nullptr); + + std::vector result; + + DBusMessageIter rootIterator; + DBusMessageIter arrayIterator; + DBusPendingCall* pendingReturn; + + DBusMessage *message = dbus_message_new_method_call("org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", "ListNames"); + if (!message) + { + LOG_ERROR("Failed to create D-Bus Message!"); + return result; + } + + dbus_message_iter_init_append(message, &rootIterator); + if (!dbus_connection_send_with_reply(connection, message, &pendingReturn, -1)) + { + LOG_ERROR("Failed to create D-Bus Message!"); + return result; + } + + if (!pendingReturn) + { + LOG_ERROR("D-Bus Pending call is null!"); + return result; + } + + dbus_connection_flush(connection); + dbus_message_unref(message); + dbus_pending_call_block(pendingReturn); + message = dbus_pending_call_steal_reply(pendingReturn); + if (!message) + { + LOG_ERROR("Failed to get D-Bus reply!"); + return result; + } + + dbus_pending_call_unref(pendingReturn); + + if (!dbus_message_iter_init(message, &rootIterator)) + { + LOG_ERROR("D-Bus message has no arguments!"); + return result; + } + + if (dbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_ARRAY) + { + LOG_ERROR("D-Bus message returned invalid type!"); + return result; + } + + dbus_message_iter_recurse(&rootIterator, &arrayIterator); + do + { + const char *rawName; + dbus_message_iter_get_basic(&arrayIterator, &rawName); + const std::string name = rawName; + if (name.starts_with("org.mpris.MediaPlayer2.")) + result.emplace_back(name); + } while (dbus_message_iter_next(&arrayIterator)); + + return result; +} + +static bool IsMediaPlayerPlaying(DBusConnection* connection, const std::string& busName) +{ + assert(connection != nullptr); + + DBusMessageIter rootIterator; + DBusMessageIter arrayIterator; + DBusPendingCall* pendingReturn; + + DBusMessage* message = dbus_message_new_method_call(busName.c_str(), "/org/mpris/MediaPlayer2", "org.freedesktop.DBus.Properties", "Get"); + if (!message) + { + LOG_ERROR("Failed to create D-Bus Message!"); + return false; + } + + auto interfaceName = "org.mpris.MediaPlayer2.Player"; + auto propertyName = "PlaybackStatus"; + + dbus_message_iter_init_append(message, &rootIterator); + if (!dbus_message_iter_append_basic(&rootIterator, DBUS_TYPE_STRING, &interfaceName)) + { + LOG_ERROR("Failed to append interface name to D-Bus Message!"); + return false; + } + + if (!dbus_message_iter_append_basic(&rootIterator, DBUS_TYPE_STRING, &propertyName)) + { + LOG_ERROR("Failed to append property name to D-Bus Message!"); + return false; + } + + if (!dbus_connection_send_with_reply(connection, message, &pendingReturn, -1)) + { + LOG_ERROR("Failed to create D-Bus Message!"); + return false; + } + + if (!pendingReturn) + { + LOG_ERROR("D-Bus Pending call is null!"); + return false; + } + + dbus_connection_flush(connection); + dbus_message_unref(message); + dbus_pending_call_block(pendingReturn); + message = dbus_pending_call_steal_reply(pendingReturn); + if (!message) + { + LOG_ERROR("Failed to get D-Bus reply!"); + return false; + } + + dbus_pending_call_unref(pendingReturn); + + if (!dbus_message_iter_init(message, &rootIterator)) + { + LOG_ERROR("D-Bus message has no arguments!"); + return false; + } + + if (dbus_message_iter_get_arg_type(&rootIterator) != DBUS_TYPE_VARIANT) + { + LOG_ERROR("D-Bus message returned invalid type!"); + return false; + } + + dbus_message_iter_recurse(&rootIterator, &arrayIterator); + if (dbus_message_iter_get_arg_type(&arrayIterator) != DBUS_TYPE_STRING) + { + LOG_ERROR("D-Bus message returned invalid type!"); + return false; + } + + const char *rawStatus; + dbus_message_iter_get_basic(&arrayIterator, &rawStatus); + const std::string status = rawStatus; + return status == "Playing"; +} + bool os::media::IsExternalMediaPlaying() { + const auto dbusConnection = CreateDBusConnection(); + if (!dbusConnection) + return false; + + std::vector busNames = GetMediaPlayerBusNames(dbusConnection); + for (const auto& bus : busNames) + { + if (IsMediaPlayerPlaying(dbusConnection, bus)) + return true; + } + + DestroyDBusConnection(dbusConnection); + return false; -} +} \ No newline at end of file