Skip to content

Commit

Permalink
FIX(client,mac): Add support for input/output device switching on macOS
Browse files Browse the repository at this point in the history
Previously, when switching input/output devices at the system level, Mumble would ignore the switch and continue to use the previous device. This patch adds support for proper device switching, allowing Mumble to correctly follow the system input/output device.

Fixes #1013
  • Loading branch information
jlsalmon committed Sep 30, 2021
1 parent 296956c commit a5dece1
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 0 deletions.
4 changes: 4 additions & 0 deletions src/mumble/CoreAudio.h
Expand Up @@ -45,6 +45,8 @@ class CoreAudioInput : public AudioInput {
AudioBufferList buflist{};
static void propertyChange(void *udata, AudioUnit au, AudioUnitPropertyID prop, AudioUnitScope scope,
AudioUnitElement element);
static OSStatus deviceChange(AudioObjectID inObjectID, UInt32 inNumberAddresses,
const AudioObjectPropertyAddress inAddresses[], void *udata);
static OSStatus inputCallback(void *udata, AudioUnitRenderActionFlags *flags, const AudioTimeStamp *ts,
UInt32 busnum, UInt32 npackets, AudioBufferList *buflist);

Expand All @@ -64,6 +66,8 @@ class CoreAudioOutput : public AudioOutput {
AudioUnit auHAL{};
static void propertyChange(void *udata, AudioUnit au, AudioUnitPropertyID prop, AudioUnitScope scope,
AudioUnitElement element);
static OSStatus deviceChange(AudioObjectID inObjectID, UInt32 inNumberAddresses,
const AudioObjectPropertyAddress inAddresses[], void *udata);
static OSStatus outputCallback(void *udata, AudioUnitRenderActionFlags *flags, const AudioTimeStamp *ts,
UInt32 busnum, UInt32 npackets, AudioBufferList *buflist);

Expand Down
49 changes: 49 additions & 0 deletions src/mumble/CoreAudio.mm
Expand Up @@ -825,6 +825,14 @@ static void LogAUStreamDescription(AudioUnit au) {
"events.");
}

AudioObjectPropertyAddress inputDeviceAddress = {
kAudioHardwarePropertyDefaultInputDevice,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
CHECK_WARN(AudioObjectAddPropertyListener(kAudioObjectSystemObject, &inputDeviceAddress, CoreAudioInput::deviceChange, this),
"CoreAudioInput: Unable to create input device change listener. Unable to listen to device changes.");

buflist.mNumberBuffers = 1;
AudioBuffer *b = buflist.mBuffers;
b->mNumberChannels = iMicChannels;
Expand Down Expand Up @@ -916,6 +924,23 @@ static void LogAUStreamDescription(AudioUnit au) {
}
}

OSStatus CoreAudioInput::deviceChange(AudioObjectID inObjectID, UInt32 inNumberAddresses,
const AudioObjectPropertyAddress inAddresses[], void *udata) {
Q_UNUSED(inObjectID);
Q_UNUSED(inNumberAddresses);
Q_UNUSED(inAddresses);

CoreAudioInput *o = reinterpret_cast< CoreAudioInput * >(udata);
if (!o->bRunning) return noErr;

qWarning("CoreAudioInput: Input device change detected. Restarting AudioInput.");
Audio::stopInput();
Audio::startInput();

return noErr;
}


CoreAudioOutput::CoreAudioOutput() {
}

Expand Down Expand Up @@ -1017,6 +1042,14 @@ static void LogAUStreamDescription(AudioUnit au) {
CHECK_WARN(AudioUnitAddPropertyListener(auHAL, kAudioUnitProperty_StreamFormat, CoreAudioOutput::propertyChange, this),
"CoreAudioOutput: Unable to create output property change listener. Unable to listen to property changes.");

AudioObjectPropertyAddress outputDeviceAddress = {
kAudioHardwarePropertyDefaultOutputDevice,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
CHECK_WARN(AudioObjectAddPropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, CoreAudioOutput::deviceChange, this),
"CoreAudioOutput: Unable to create output device change listener. Unable to listen to device changes.");

AURenderCallbackStruct cb;
cb.inputProc = CoreAudioOutput::outputCallback;
cb.inputProcRefCon = this;
Expand Down Expand Up @@ -1108,3 +1141,19 @@ static void LogAUStreamDescription(AudioUnit au) {
qWarning("CoreAudioOutput: Unexpected property changed event received.");
}
}

OSStatus CoreAudioOutput::deviceChange(AudioObjectID inObjectID, UInt32 inNumberAddresses,
const AudioObjectPropertyAddress inAddresses[], void *udata) {
Q_UNUSED(inObjectID);
Q_UNUSED(inNumberAddresses);
Q_UNUSED(inAddresses);

CoreAudioOutput *o = reinterpret_cast< CoreAudioOutput * >(udata);
if (!o->bRunning) return noErr;

qWarning("CoreAudioOutput: Output device change detected. Restarting AudioOutput.");
Audio::stopOutput();
Audio::startOutput();

return noErr;
}

0 comments on commit a5dece1

Please sign in to comment.