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

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{ ...@@ -287,3 +287,8 @@ win32-msvc{
INCLUDEPATH += $$PWD/lib/RtAudio/include INCLUDEPATH += $$PWD/lib/RtAudio/include
LIBS += -L$$PWD/lib/RtAudio/lib -lrtaudio LIBS += -L$$PWD/lib/RtAudio/lib -lrtaudio
win32: LIBS += -lole32 -lwinmm -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid win32: LIBS += -lole32 -lwinmm -lksuser -lmfplat -lmfuuid -lwmcodecdspuuid
macx{
# Needed by the SystemVolume class
LIBS += -framework CoreAudio
}
#include "systemvolume.h" #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() { SystemVolume::SystemVolume() {
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
...@@ -22,8 +47,39 @@ SystemVolume::SystemVolume() { ...@@ -22,8 +47,39 @@ SystemVolume::SystemVolume() {
return; return;
} }
#endif #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); startTimer(SystemVolumeUpdateRateInMs);
timerEvent(nullptr); timerEvent(nullptr);
#endif
} }
void SystemVolume::timerEvent(QTimerEvent * /*event*/) { void SystemVolume::timerEvent(QTimerEvent * /*event*/) {
...@@ -43,6 +99,7 @@ void SystemVolume::timerEvent(QTimerEvent * /*event*/) { ...@@ -43,6 +99,7 @@ void SystemVolume::timerEvent(QTimerEvent * /*event*/) {
} }
SystemVolume::~SystemVolume() { SystemVolume::~SystemVolume() {
#ifdef Q_OS_WIN
if (pEnumerator) { if (pEnumerator) {
pEnumerator->Release(); pEnumerator->Release();
} }
...@@ -56,6 +113,7 @@ SystemVolume::~SystemVolume() { ...@@ -56,6 +113,7 @@ SystemVolume::~SystemVolume() {
client->Release(); client->Release();
} }
CoUninitialize(); CoUninitialize();
#endif
} }
void SystemVolume::setVolume(double volume) { void SystemVolume::setVolume(double volume) {
...@@ -67,6 +125,26 @@ void SystemVolume::setVolume(double volume) { ...@@ -67,6 +125,26 @@ void SystemVolume::setVolume(double volume) {
if (endpointVolume) { if (endpointVolume) {
endpointVolume->SetMasterVolumeLevelScalar(static_cast<float>(volume), nullptr); 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 #endif
} }
} }
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
#include <windows.h> #include <windows.h>
#endif #endif
#ifdef Q_OS_MAC
#include <CoreAudio/CoreAudio.h>
#endif
class SystemVolume : public QObject { class SystemVolume : public QObject {
Q_OBJECT Q_OBJECT
#ifdef Q_OS_WIN #ifdef Q_OS_WIN
...@@ -22,6 +26,9 @@ class SystemVolume : public QObject { ...@@ -22,6 +26,9 @@ class SystemVolume : public QObject {
IAudioEndpointVolume *endpointVolume = nullptr; IAudioEndpointVolume *endpointVolume = nullptr;
WAVEFORMATEX *wformat = nullptr; WAVEFORMATEX *wformat = nullptr;
IAudioClient *client = nullptr; IAudioClient *client = nullptr;
#endif
#ifdef Q_OS_MAC
AudioDeviceID defaultOutputDeviceID = kAudioDeviceUnknown;
#endif #endif
double volume = -1; double volume = -1;
Q_PROPERTY(double volume READ getVolume WRITE setVolume NOTIFY volumeChanged) 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