From dc7ce7f01fe17b331ee4841e03ebb5f077adc1a2 Mon Sep 17 00:00:00 2001 From: Art Pinch Date: Mon, 7 Dec 2020 10:55:01 +0300 Subject: [PATCH] [SystemVolumePlugin][MacOS] Send data about default audio device --- .../systemvolume/systemvolumeplugin-macos.cpp | 59 ++++++++++++++++++- .../systemvolume/systemvolumeplugin-macos.h | 2 + 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/plugins/systemvolume/systemvolumeplugin-macos.cpp b/plugins/systemvolume/systemvolumeplugin-macos.cpp index 7bf2b73d5..461d550f9 100644 --- a/plugins/systemvolume/systemvolumeplugin-macos.cpp +++ b/plugins/systemvolume/systemvolumeplugin-macos.cpp @@ -33,6 +33,8 @@ public: float volume(); void setMuted(bool muted); bool isMuted(); + void setDefault(bool enabled); + bool isDefault(); void updateType(); }; @@ -79,6 +81,12 @@ static const AudioObjectPropertyAddress kAudioMasterDataSourcePropertyAddress = kAudioObjectPropertyElementMaster }; +static const AudioObjectPropertyAddress kAudioDefaultOutputDevicePropertyAddress = { + kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, + kAudioObjectPropertyElementMaster +}; + OSStatus onVolumeChanged(AudioObjectID object, UInt32 numAddresses, const AudioObjectPropertyAddress addresses[], void *context) { Q_UNUSED(object); @@ -101,6 +109,17 @@ OSStatus onMutedChanged(AudioObjectID object, UInt32 numAddresses, const AudioOb return noErr; } +OSStatus onDefaultChanged(AudioObjectID object, UInt32 numAddresses, const AudioObjectPropertyAddress addresses[], void *context) +{ + Q_UNUSED(object); + Q_UNUSED(addresses); + Q_UNUSED(numAddresses); + + SystemvolumePlugin *plugin = (SystemvolumePlugin*)context; + plugin->sendSinkList(); + return noErr; +} + OSStatus onOutputSourceChanged(AudioObjectID object, UInt32 numAddresses, const AudioObjectPropertyAddress addresses[], void *context) { Q_UNUSED(object); @@ -112,6 +131,16 @@ OSStatus onOutputSourceChanged(AudioObjectID object, UInt32 numAddresses, const return noErr; } +AudioObjectID getDefaultOutputDeviceId() { + AudioObjectID dataSourceId; + UInt32 size = sizeof(dataSourceId); + OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &kAudioDefaultOutputDevicePropertyAddress, 0, NULL, &size, &dataSourceId); + if (result != noErr) + return kAudioDeviceUnknown; + + return dataSourceId; +} + UInt32 getDeviceSourceId(AudioObjectID deviceId) { UInt32 dataSourceId; UInt32 size = sizeof(dataSourceId); @@ -202,6 +231,11 @@ SystemvolumePlugin::SystemvolumePlugin(QObject* parent, const QVariantList& args : KdeConnectPlugin(parent, args), m_sinksMap() {} +SystemvolumePlugin::~SystemvolumePlugin() +{ + AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &kAudioDefaultOutputDevicePropertyAddress, &onDefaultChanged, (void *)this); +} + bool SystemvolumePlugin::receivePacket(const NetworkPacket& np) { if (np.has(QStringLiteral("requestSinks"))) { @@ -260,7 +294,8 @@ void SystemvolumePlugin::sendSinkList() {QStringLiteral("muted"), audioDevice->isMuted()}, {QStringLiteral("description"), audioDevice->m_description}, {QStringLiteral("volume"), audioDevice->volume() * 100}, - {QStringLiteral("maxVolume"), 100} + {QStringLiteral("maxVolume"), 100}, + {QStringLiteral("enabled"), audioDevice->isDefault()} }; array.append(sinkObject); @@ -275,6 +310,7 @@ void SystemvolumePlugin::sendSinkList() void SystemvolumePlugin::connected() { + AudioObjectAddPropertyListener(kAudioObjectSystemObject, &kAudioDefaultOutputDevicePropertyAddress, &onDefaultChanged, (void *)this); sendSinkList(); } @@ -369,6 +405,22 @@ void MacOSCoreAudioDevice::setMuted(bool muted) } } +void MacOSCoreAudioDevice::setDefault(bool enabled) +{ + if (!enabled) return; + + if (m_deviceId == kAudioObjectUnknown) { + qWarning(KDECONNECT_PLUGIN_SYSTEMVOLUME) << "Unable to set an Unknown Device as default output"; + return; + } + + OSStatus result = AudioObjectSetPropertyData(kAudioObjectSystemObject, &kAudioDefaultOutputDevicePropertyAddress, 0, NULL, sizeof(m_deviceId), &m_deviceId); + + if (result != noErr) { + qWarning(KDECONNECT_PLUGIN_SYSTEMVOLUME) << "Unable to set default state of Device" << m_deviceId; + } +} + float MacOSCoreAudioDevice::volume() { OSStatus result; @@ -412,6 +464,11 @@ bool MacOSCoreAudioDevice::isMuted() return muted == 1; } +bool MacOSCoreAudioDevice::isDefault() { + AudioObjectID defaultDeviceId = getDefaultOutputDeviceId(); + return m_deviceId == defaultDeviceId; +} + void MacOSCoreAudioDevice::updateType() { // Try to get volume from left channel to check if it's a stereo device diff --git a/plugins/systemvolume/systemvolumeplugin-macos.h b/plugins/systemvolume/systemvolumeplugin-macos.h index 1d8a59f82..fd818580a 100644 --- a/plugins/systemvolume/systemvolumeplugin-macos.h +++ b/plugins/systemvolume/systemvolumeplugin-macos.h @@ -25,6 +25,8 @@ class Q_DECL_EXPORT SystemvolumePlugin : public KdeConnectPlugin public: explicit SystemvolumePlugin(QObject *parent, const QVariantList &args); + ~SystemvolumePlugin(); + bool receivePacket(const NetworkPacket& np) override; void connected() override; void sendSinkList();