Skip to content

πŸ”Š A Swift framework that aims to make Core Audio use less tedious in macOS

License

Notifications You must be signed in to change notification settings

carescribe/SimplyCoreAudio

Β 
Β 

Repository files navigation

Carescribe fork notes

This is a fork of the original project because

At time of publishing, the develop branch of this library do not support use cases in CLI applications. A PR was merged that fixed this this but various code changes from 9th April on the develop branch broke other parts of the library. The main branch in this fork removes those changes and keeps only the fixes to PR 51.[]

πŸ”Š SimplyCoreAudio

Platform Swift support Swift Package Manager compatible GitHub tag License

SimplyCoreAudio (formerly known as AMCoreAudio) is a Swift framework that aims to make Core Audio use less tedious in macOS.

Features

  • Enumerating audio devices (see SimplyCoreAudio)
  • Getting/setting default input, output and system device (see SimplyCoreAudio)
  • Creating and destroying aggregate devices (see SimplyCoreAudio)
  • Querying audio device properties such as: name, manufacturer, UID, volume, mute, sample rate, clock source, etc. (see AudioDevice)
  • Managing (physical and virtual) audio streams associated to an audio device (see AudioStream)
  • Subscribing to audio hardware, audio device, and audio stream notifications (see Notification Extensions)

Resources

Requirements

  • Xcode 12+
  • Swift 4.0+
  • macOS 10.12+

Installation

To install the Swift Package, please follow the steps below:

  • Add https://github.com/rnine/SimplyCoreAudio.git as a Swift Package Manager dependency to your project.
  • When asked to Choose Package Options, use the default settings provided by Xcode.
  • When asked to Add Package, add SimplyCoreAudio to your desired target(s).

Usage

  1. Import SimplyCoreAudio

    import SimplyCoreAudio
  2. Instantiate SimplyCoreAudio

    let simplyCA = SimplyCoreAudio()
  3. Interact with SimplyCoreAudio

    // Get the default output device
    let device = simplyCA.defaultOutputDevice
    
    // Get preferred output channels
    if let stereoPair = device.preferredChannelsForStereo(scope: .output) {
        let leftChannel = stereoPair.left
        let rightChannel = stereoPair.right
        // Use channels...
    }
    
    // Get device samplerate
    if let sampleRate = device.nominalSampleRate {
        // Use samplerate...
    }
    
    // Get device virtual master volume
    if let outVolume = device.virtualMasterVolume(scope: .output) {
        // Use output volume...
    }
  4. Subscribe to hardware-related notifications

    // e.g., subscribing to `deviceListChanged` notification.
    var observer = NotificationCenter.default.addObserver(forName: .deviceListChanged,
                                                           object: nil,
                                                            queue: .main) { (notification) in
        // Get added devices.
        guard let addedDevices = notification.userInfo?["addedDevices"] as? [AudioDevice] else { return }
    
        // Get removed devices.
        guard let removedDevices = notification.userInfo?["removedDevices"] as? [AudioDevice] else { return }
    }
    
    // Once done observing, remove observer and nil it.
    NotificationCenter.default.removeObserver(observer)
    observer = nil
  5. Subscribe to notifications from a specific audio device

    // Get the default output device
    let device = simplyCA.defaultOutputDevice
    
    // e.g., subscribing to `deviceNominalSampleRateDidChange` notification.
    var observer = NotificationCenter.default.addObserver(forName: .deviceNominalSampleRateDidChange,
                                                           object: device,
                                                            queue: .main) { (notification) in
        // Handle notification.
    }
    
    // Once done observing, remove observer and nil it.
    NotificationCenter.default.removeObserver(observer)
    observer = nil
  6. Subscribe to notifications from a specific audio stream

    // Get the default output device
    let device = simplyCA.defaultOutputDevice
    
    // Get the first output stream
    guard let streams = device.streams(scope: .output) else { return }
    guard let stream0 = streams.first else { return }
    
    // e.g., subscribing to `streamPhysicalFormatDidChange` notification.
    var observer = NotificationCenter.default.addObserver(forName: .streamPhysicalFormatDidChange,
                                                           object: stream0,
                                                            queue: .main) { (notification) in
        // Handle notification.
    }
    
    // Once done observing, remove observer and nil it.
    NotificationCenter.default.removeObserver(observer)
    observer = nil

Supported Notifications

Audio Hardware Notifications

Name Purpose User Info
defaultInputDeviceChanged Called whenever the default input device changes. N/A
defaultOutputDeviceChanged Called whenever the default output device changes. N/A
defaultSystemOutputDeviceChanged Called whenever the default system output device changes. N/A
deviceListChanged Called whenever the list of hardware devices and device subdevices changes. addedDevices: [AudioDevice], removedDevices: [AudioDevice]

Audio Device Notifications

Name Purpose User Info
deviceNominalSampleRateDidChange Called whenever the audio device's sample rate changes. N/A
deviceAvailableNominalSampleRatesDidChange Called whenever the audio device's list of nominal sample rates changes. N/A
deviceClockSourceDidChange Called whenever the audio device's clock source changes. N/A
deviceNameDidChange Called whenever the audio device's name changes.
deviceOwnedObjectsDidChange Called whenever the list of owned audio devices on this audio device changes. N/A
deviceVolumeDidChange Called whenever the audio device's volume for a given channel and scope changes. channel: UInt32, scope: Scope
deviceMuteDidChange Called whenever the audio device's mute state for a given channel and scope changes. channel: UInt32, scope: Scope
deviceIsAliveDidChange Called whenever the audio device's list of nominal sample rates changes. N/A
deviceIsRunningDidChange Called whenever the audio device's is running property changes. N/A
deviceIsRunningSomewhereDidChange Called whenever the audio device's is running somewhere property changes. N/A
deviceIsJackConnectedDidChange Called whenever the audio device's is jack connected property changes. N/A
devicePreferredChannelsForStereoDidChange Called whenever the audio device's preferred channels for stereo property changes. N/A
deviceHogModeDidChange Called whenever the audio device's hog mode property changes. N/A

Audio Stream Notifications

Name Purpose User Info
streamIsActiveDidChange Called whenever the audio stream isActive flag changes state. N/A
streamPhysicalFormatDidChange Called whenever the audio stream physical format changes. N/A

Further Development & Patches

Do you want to contribute to the project? Please fork, patch, and then submit a pull request!

Running Tests

Please make sure to install NullAudio.driver before attempting to run tests:

Installing NullAudio.driver

  1. Unzip NullAudio.driver.zip and install driver into the system HAL Plug-Ins folder

    sudo unzip Tests/Extras/NullAudio.driver.zip -d /Library/Audio/Plug-Ins/HAL
  2. Reload coreaudiod

    sudo launchctl kill KILL system/com.apple.audio.coreaudiod

Demo Project

  • SimplyCoreAudioDemo β€” a basic SwiftUI-based demo showcasing device enumeration and notifications.

License

SimplyCoreAudio was written by Ruben Nine (@rnine) in 2013-2014 (open-sourced in March 2014) and is licensed under the MIT license. See LICENSE.md.

About

πŸ”Š A Swift framework that aims to make Core Audio use less tedious in macOS

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Swift 95.8%
  • Shell 4.2%