Skip to content

Instantly share code, notes, and snippets.

@ConfusedVorlon
Created June 8, 2020 21:42
Show Gist options
  • Save ConfusedVorlon/8cefb0c623142837206f7f6507e7c3f4 to your computer and use it in GitHub Desktop.
Save ConfusedVorlon/8cefb0c623142837206f7f6507e7c3f4 to your computer and use it in GitHub Desktop.
//
// AudioDeviceNotifier.swift
//
// Created by Rob Jonson on 20/01/2017.
// Copyright © 2017 HobbyistSoftware. All rights reserved.
//
import Foundation
import CoreAudio
/// Provides notification when the default audio device changes, or when the stream settings of the default audio device change
class AudioDeviceNotifier {
var active = true
var handler:(()->(Void))?
private var listenerBlock:AudioObjectPropertyListenerBlock?
private var streamBlock:AudioObjectPropertyListenerBlock?
private var audioDevicesAddress = AudioObjectPropertyAddress.init(mSelector: kAudioHardwarePropertyDefaultOutputDevice,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster)
private var currentAudioDevice:AudioDevice? {
didSet {
if oldValue != currentAudioDevice {
moveStreamNotifier(from: oldValue, to:currentAudioDevice )
}
}
}
init() {
listenerBlock = {
[weak self] (numberOfElements, pointerToArrayOfAddresses) in
print("Default device changed")
self?.deviceChanged()
}
streamBlock = {
[weak self] (numberOfElements, pointerToArrayOfAddresses) in
print("Stream details changed")
self?.deviceChanged()
}
let err = AudioObjectAddPropertyListenerBlock(AudioObjectID(kAudioObjectSystemObject), &audioDevicesAddress, DispatchQueue.main,listenerBlock!)
currentAudioDevice = AudioDevice.defaultOutputDevice()
moveStreamNotifier(from: nil, to: currentAudioDevice)
if err != noErr {
print("Failed to register audio block")
}
}
deinit {
AudioObjectRemovePropertyListenerBlock(AudioObjectID(kAudioObjectSystemObject),
&audioDevicesAddress,
DispatchQueue.main,listenerBlock!)
moveStreamNotifier(from: currentAudioDevice, to: nil)
}
func deviceChanged() {
currentAudioDevice = AudioDevice.defaultOutputDevice()
if active {
handler?()
}
}
func moveStreamNotifier(from:AudioDevice?, to:AudioDevice?) {
var audioDeviceStreamsAddress = AudioObjectPropertyAddress.init(mSelector: kAudioDevicePropertyStreamFormat,
mScope: kAudioObjectPropertyScopeOutput,
mElement: kAudioObjectPropertyElementMaster)
if let streamBlock = streamBlock {
if let from = from {
let err = AudioObjectRemovePropertyListenerBlock(from.id,
&audioDeviceStreamsAddress,
DispatchQueue.main,streamBlock)
if err != noErr {
print("Error removing listening block")
}
}
if let to = to {
print("moving notifier to \(String(describing: to.name())))")
let err = AudioObjectAddPropertyListenerBlock(to.id,
&audioDeviceStreamsAddress,
DispatchQueue.main,streamBlock)
if err != noErr {
print("Error adding listening block")
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment