macoscocoaswiftaudiotoolbox

Using AudioToolbox from Swift to access OS X master volume


Is there a solution to setting the system's master volume from within my Swift app?

I read a lot about AudioToolbox and read some source examples in Objective-C. For example, I found this: Setting Mac OS X Volume Programatically after 10.6

But I can't get it working in Swift.

I am missing some example code in https://developer.apple.com/library/mac/documentation/AudioToolbox/Reference/AudioHardwareServicesReference/index.html#//apple_ref/c/func/AudioHardwareServiceGetPropertyData


Solution

  • (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().