Set Os X Volume in Os X 10.11 Using Swift Without Using the Deprecated Audiohardwareservicesetpropertydata API

Set OS X volume in OS X 10.11 using Swift without using the deprecated AudioHardwareServiceSetPropertyData API

As also suggested in this answer to a similar Objective-C question, I'd suggest using ISSoundAdditions, which you can call from Swift as such:

NSSound.setSystemVolume(0.5)

The implementation of -setSystemVolume begins around line 113 in ISSoundAdditions.m in case you're curious of how they accomplish setting the system volume.

To clarify a factually challenged comment to my answer (since deleted, apparently), there is no use of deprecated APIs in ISSoundAdditions when compiling with the El Capitan SDK – AudioHardwareServiceSetPropertyData is not used. AudioObjectSetPropertyData is indeed the API one should switch to if using the deprecated AudioHardwareServiceSetPropertyData, though as you can see from the ISSoundAdditions implementation I linked to, there's a bit of work involved (hence I linked to the implementation in the first place).

Capture system volume changes in Swift

I used (Swift 4):

DistributedNotificationCenter.default.addObserver(self,
selector: #selector(eventFunction(_:)),
name: NSNotification.Name(rawValue: "com.apple.sound.settingsChangedNotification"),
object: nil)

Where the function is defined like:

@objc func volumeChangeEvent(_ evt: NSEvent) { }

Using AudioToolbox from Swift to access OS X master volume

(Code updated for Swift 4 and later, the Swift 2 and 3 versions can be found in the edit history.)

This is what I got from translating the answers to Change OS X system volume programmatically and Setting Mac OS X volume programmatically after 10.6 (Snow Leopard) to Swift (error checking omitted for brevity):

Required framework:

import AudioToolbox

Get default output device:

var defaultOutputDeviceID = AudioDeviceID(0)
var defaultOutputDeviceIDSize = UInt32(MemoryLayout.size(ofValue: defaultOutputDeviceID))

var getDefaultOutputDevicePropertyAddress = AudioObjectPropertyAddress(
mSelector: kAudioHardwarePropertyDefaultOutputDevice,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: AudioObjectPropertyElement(kAudioObjectPropertyElementMaster))

let status1 = AudioObjectGetPropertyData(
AudioObjectID(kAudioObjectSystemObject),
&getDefaultOutputDevicePropertyAddress,
0,
nil,
&defaultOutputDeviceIDSize,
&defaultOutputDeviceID)

Set volume:

var volume = Float32(0.50) // 0.0 ... 1.0
var volumeSize = UInt32(MemoryLayout.size(ofValue: volume))

var volumePropertyAddress = AudioObjectPropertyAddress(
mSelector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
mScope: kAudioDevicePropertyScopeOutput,
mElement: kAudioObjectPropertyElementMaster)

let status2 = AudioObjectSetPropertyData(
defaultOutputDeviceID,
&volumePropertyAddress,
0,
nil,
volumeSize,
&volume)

Finally, for the sake of completeness, get the volume:

var volume = Float32(0.0)
var volumeSize = UInt32(MemoryLayout.size(ofValue: volume))

var volumePropertyAddress = AudioObjectPropertyAddress(
mSelector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
mScope: kAudioDevicePropertyScopeOutput,
mElement: kAudioObjectPropertyElementMaster)

let status3 = AudioObjectGetPropertyData(
defaultOutputDeviceID,
&volumePropertyAddress,
0,
nil,
&volumeSize,
&volume)

print(volume)

Error checking has been omitted for brevity. Of course one should check the status return values for success or failure in a real application.

Credits go to Set OS X volume in OS X 10.11 using Swift without using the deprecated AudioHardwareServiceSetPropertyData API for using AudioObjectSetPropertyData()
instead of the deprecated AudioHardwareServiceSetPropertyData().

As noamtm mentions in the comments, this works also for getting and setting the left-right balance, by passing

mSelector: kAudioHardwareServiceDeviceProperty_VirtualMasterBalance

to AudioObjectPropertyAddress().



Related Topics



Leave a reply



Submit