Implement music attenuation for Linux

This commit is contained in:
wAABBsif 2026-01-20 23:09:32 -05:00
parent d28dab8840
commit 43da7d33f3

View file

@ -2,7 +2,188 @@
#include <os/logger.h>
#include <dbus/dbus.h>
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<std::string> GetMediaPlayerBusNames(DBusConnection* connection)
{
assert(connection != nullptr);
std::vector<std::string> 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<std::string> busNames = GetMediaPlayerBusNames(dbusConnection);
for (const auto& bus : busNames)
{
if (IsMediaPlayerPlaying(dbusConnection, bus))
return true;
}
DestroyDBusConnection(dbusConnection);
return false;
}
}