Commit 13015c2b authored by Leander Schulten's avatar Leander Schulten

SystemVolume: Add implementation for macOS with CoreAudio

parent 87188e11
Pipeline #199356 passed with stage
in 5 minutes and 51 seconds
......@@ -287,3 +287,8 @@ win32-msvc{
INCLUDEPATH += $$PWD/lib/RtAudio/include
LIBS += -L$$PWD/lib/RtAudio/lib -lrtaudio
win32: LIBS += -lole32 -lwinmm -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid
macx{
# Needed by the SystemVolume class
LIBS += -framework CoreAudio
}
#include "systemvolume.h"
#ifdef Q_OS_MAC
#include <QtDebug>
#endif
#ifdef Q_OS_MAC
OSStatus callback(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void * /*inClientData*/) {
for (UInt32 i = 0; i < inNumberAddresses; ++i) {
const auto &cur = inAddresses[i];
if (cur.mScope == kAudioDevicePropertyScopeOutput && cur.mSelector == kAudioDevicePropertyVolumeScalar && cur.mElement == 1 /*LEFT_CHANNEL*/) {
AudioObjectPropertyAddress volumePropertyAddress = {
kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, 1 /*LEFT_CHANNEL*/
};
Float32 volume;
UInt32 volumedataSize = sizeof(volume);
auto result = AudioObjectGetPropertyData(inObjectID, &volumePropertyAddress, 0, nullptr, &volumedataSize, &volume);
if (result == kAudioHardwareNoError) {
SystemVolume::get().setVolume(static_cast<double>(volume));
}
break;
}
}
return noErr;
}
#endif
SystemVolume::SystemVolume() {
#ifdef Q_OS_WIN
......@@ -22,8 +47,39 @@ SystemVolume::SystemVolume() {
return;
}
#endif
#ifdef Q_OS_MAC
AudioObjectPropertyAddress getDefaultOutputDevicePropertyAddress = {kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster};
UInt32 outputDeviceSize = sizeof(defaultOutputDeviceID);
OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &getDefaultOutputDevicePropertyAddress, 0, nullptr, &outputDeviceSize, &defaultOutputDeviceID);
if (kAudioHardwareNoError != result) {
qWarning() << "Failed to get the default output device";
}
// register a listener so that we get an event when the volume changed
AudioObjectPropertyAddress volumePropertyAddress = {
kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, 1 /*LEFT_CHANNEL*/
};
result = AudioObjectAddPropertyListener(defaultOutputDeviceID, &volumePropertyAddress, &callback, nullptr);
if (result != kAudioHardwareNoError) {
qWarning() << "Registration of Audio Listener Failed";
}
// get initial volume
Float32 volume;
UInt32 volumedataSize = sizeof(volume);
result = AudioObjectGetPropertyData(defaultOutputDeviceID, &volumePropertyAddress, 0, nullptr, &volumedataSize, &volume);
if (result == kAudioHardwareNoError) {
this->volume = static_cast<double>(volume);
emit volumeChanged();
}
#else
// we don't need polling on mac, we have a callback
startTimer(SystemVolumeUpdateRateInMs);
timerEvent(nullptr);
#endif
}
void SystemVolume::timerEvent(QTimerEvent * /*event*/) {
......@@ -43,6 +99,7 @@ void SystemVolume::timerEvent(QTimerEvent * /*event*/) {
}
SystemVolume::~SystemVolume() {
#ifdef Q_OS_WIN
if (pEnumerator) {
pEnumerator->Release();
}
......@@ -56,6 +113,7 @@ SystemVolume::~SystemVolume() {
client->Release();
}
CoUninitialize();
#endif
}
void SystemVolume::setVolume(double volume) {
......@@ -67,6 +125,26 @@ void SystemVolume::setVolume(double volume) {
if (endpointVolume) {
endpointVolume->SetMasterVolumeLevelScalar(static_cast<float>(volume), nullptr);
}
#endif
#ifdef Q_OS_MAC
if (defaultOutputDeviceID != kAudioDeviceUnknown) {
AudioObjectPropertyAddress volumePropertyAddress = {
kAudioDevicePropertyVolumeScalar, kAudioDevicePropertyScopeOutput, 1 /*LEFT_CHANNEL*/
};
Float32 volume = static_cast<Float32>(this->volume);
auto result = AudioObjectSetPropertyData(defaultOutputDeviceID, &volumePropertyAddress, 0, nullptr, sizeof(volume), &volume);
if (result != kAudioHardwareNoError) {
qWarning() << "Can not set system volume";
} else {
// setting right channel
volumePropertyAddress.mElement = 2 /*RIGHT_CHANNEL*/;
result = AudioObjectSetPropertyData(defaultOutputDeviceID, &volumePropertyAddress, 0, nullptr, sizeof(volume), &volume);
if (result != kAudioHardwareNoError) {
qWarning() << "Can not set system volume of right channel";
}
}
}
#endif
}
}
......@@ -14,6 +14,10 @@
#include <windows.h>
#endif
#ifdef Q_OS_MAC
#include <CoreAudio/CoreAudio.h>
#endif
class SystemVolume : public QObject {
Q_OBJECT
#ifdef Q_OS_WIN
......@@ -22,6 +26,9 @@ class SystemVolume : public QObject {
IAudioEndpointVolume *endpointVolume = nullptr;
WAVEFORMATEX *wformat = nullptr;
IAudioClient *client = nullptr;
#endif
#ifdef Q_OS_MAC
AudioDeviceID defaultOutputDeviceID = kAudioDeviceUnknown;
#endif
double volume = -1;
Q_PROPERTY(double volume READ getVolume WRITE setVolume NOTIFY volumeChanged)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment