Skip to content
This repository has been archived by the owner on Mar 23, 2024. It is now read-only.

Commit

Permalink
Merge pull request #43 from donaldguy/master2main
Browse files Browse the repository at this point in the history
Replace instances of [mM]aster with [mM]ain, w/ fallbacks; Fixes #42
  • Loading branch information
rnine authored Jul 31, 2021
2 parents c3bd165 + 8c17865 commit ba8b651
Show file tree
Hide file tree
Showing 16 changed files with 151 additions and 94 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

| Version | Description | Date |
| -------------:|:------------- |:--------:|
| 4.1.0 | Following upstream changes in AudioToolbox and deprecations (as of macOS 12.0) in CoreAudio, switched all (swift) instances of `master` and `Master` to respective `main` & `Main`; <br />added deprecated versions of call-sites for backwards compatibility (with warnings) until 5.0 (@donaldguy) | July 30, 2021 |
| ----- | ----------------------------- **UNRELEASED** ------------------------------------ | -------- |
| 4.0.1 | Fixed typo in `AudioHardware.allOutputDevices` (@mattgreen) | April 9th, 2021 |
| | Minor optimizations in `AudioObject` property listeners. ||
| 4.0.0 | `AMCoreAudio` is now called 🔊 `SimplyCoreAudio` | March 27th, 2021 |
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ To install the Swift Package, please follow the steps below:
// Use samplerate...
}

// Get device virtual master volume
if let outVolume = device.virtualMasterVolume(scope: .output) {
// Get device virtual main volume
if let outVolume = device.virtualMainVolume(scope: .output) {
// Use output volume...
}
```
Expand Down
2 changes: 1 addition & 1 deletion Sources/SimplyCoreAudio/Internal/AudioHardware.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ final class AudioHardware {
let address = AudioObjectPropertyAddress(
mSelector: kAudioHardwarePropertyDevices,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster
mElement: kAudioObjectPropertyElementMain
)

let systemObjectID = AudioObjectID(kAudioObjectSystemObject)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import os.log
extension AudioObject {
class func address(selector: AudioObjectPropertySelector,
scope: AudioObjectPropertyScope = kAudioObjectPropertyScopeGlobal,
element: AudioObjectPropertyElement = kAudioObjectPropertyElementMaster) -> AudioObjectPropertyAddress {
element: AudioObjectPropertyElement = kAudioObjectPropertyElementMain) -> AudioObjectPropertyAddress {
AudioObjectPropertyAddress(mSelector: selector, mScope: scope, mElement: element)
}

Expand Down Expand Up @@ -286,13 +286,13 @@ extension AudioObject {

func address(selector: AudioObjectPropertySelector,
scope: AudioObjectPropertyScope = kAudioObjectPropertyScopeGlobal,
element: AudioObjectPropertyElement = kAudioObjectPropertyElementMaster) -> AudioObjectPropertyAddress {
element: AudioObjectPropertyElement = kAudioObjectPropertyElementMain) -> AudioObjectPropertyAddress {
AudioObject.address(selector: selector, scope: scope, element: element)
}

func validAddress(selector: AudioObjectPropertySelector,
scope: AudioObjectPropertyScope = kAudioObjectPropertyScopeGlobal,
element: AudioObjectPropertyElement = kAudioObjectPropertyElementMaster)-> AudioObjectPropertyAddress? {
element: AudioObjectPropertyElement = kAudioObjectPropertyElementMain)-> AudioObjectPropertyAddress? {
var address = self.address(selector: selector, scope: scope, element: element)

guard AudioObjectHasProperty(objectID, &address) else { return nil }
Expand Down
21 changes: 16 additions & 5 deletions Sources/SimplyCoreAudio/Public/AudioDevice+Channel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,20 @@ public extension AudioDevice {
return getProperty(address: address)
}

/// Whether the master channel is muted for a given scope.
/// Whether the main channel is muted for a given scope.
///
/// - Parameter scope: A scope.
///
/// - Returns: `true` when muted, `false` otherwise.
func isMainChannelMuted(scope: Scope) -> Bool? {
isMuted(channel: kAudioObjectPropertyElementMain, scope: scope)
}

@available(*, deprecated, renamed: "isMainChannelMuted")
func isMasterChannelMuted(scope: Scope) -> Bool? {
isMuted(channel: kAudioObjectPropertyElementMaster, scope: scope)
return isMainChannelMuted(scope: scope)
}


/// Whether a channel can be muted for a given scope.
///
Expand All @@ -184,13 +190,13 @@ public extension AudioDevice {
volumeInfo(channel: channel, scope: scope)?.canMute ?? false
}

/// Whether the master volume can be muted for a given scope.
/// Whether the main volume can be muted for a given scope.
///
/// - Parameter scope: A scope.
///
/// - Returns: `true` when the volume can be muted, `false` otherwise.
func canMuteMasterChannel(scope: Scope) -> Bool {
if canMute(channel: kAudioObjectPropertyElementMaster, scope: scope) == true {
func canMuteMainChannel(scope: Scope) -> Bool {
if canMute(channel: kAudioObjectPropertyElementMain, scope: scope) == true {
return true
}

Expand All @@ -200,6 +206,11 @@ public extension AudioDevice {

return true
}

@available(*, deprecated, renamed: "canMuteMainChannel")
func canMuteMasterChannel(scope: Scope) -> Bool? {
return canMuteMainChannel(scope: scope)
}

/// Whether a channel's volume can be set for a given scope.
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public extension AudioDevice {
let address = AudioObjectPropertyAddress(
mSelector: kAudioDevicePropertyClockSourceNameForIDCFString,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster
mElement: kAudioObjectPropertyElementMain
)

return getPropertyData(address, andValue: &translation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public extension AudioDevice {
let address = AudioObjectPropertyAddress(
mSelector: kAudioDevicePropertyDataSourceNameForIDCFString,
mScope: scope.asPropertyScope,
mElement: kAudioObjectPropertyElementMaster
mElement: kAudioObjectPropertyElementMain
)

return getPropertyData(address, andValue: &translation)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,101 +1,131 @@
//
// AudioDevice+VirtualMasterOutput.swift
// AudioDevice+VirtualMainOutput.swift
//
// Created by Ruben Nine on 20/3/21.
// Renamed from AudioDevice+VirtualMasterOutput.swift on 30/7/21
//

import AudioToolbox
import CoreAudio
import Foundation

// MARK: - 🔊 Virtual Master Output Volume / Balance Functions
// MARK: - 🔊 Virtual Main Output Volume / Balance Functions

public extension AudioDevice {
/// Whether the master volume can be set for a given scope.
/// Whether the main volume can be set for a given scope.
///
/// - Parameter scope: A scope.
///
/// - Returns: `true` when the volume can be set, `false` otherwise.
func canSetVirtualMasterVolume(scope: Scope) -> Bool {
guard validAddress(selector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
func canSetVirtualMainVolume(scope: Scope) -> Bool {
guard validAddress(selector: kAudioHardwareServiceDeviceProperty_VirtualMainVolume,
scope: scope.asPropertyScope) != nil else { return false }

return true
}

@available(*, deprecated, renamed: "canSetVirtualMainVolume")
func canSetVirtualMasterVolume(scope: Scope) -> Bool {
return canSetVirtualMainVolume(scope: scope)
}

/// Sets the virtual master volume for a given scope.
/// Sets the virtual main volume for a given scope.
///
/// - Parameter volume: The new volume as a scalar value ranging from 0 to 1.
/// - Parameter scope: A scope.
///
/// - Returns: `true` on success, `false` otherwise.
@discardableResult func setVirtualMasterVolume(_ volume: Float32, scope: Scope) -> Bool {
guard let address = validAddress(selector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
@discardableResult func setVirtualMainVolume(_ volume: Float32, scope: Scope) -> Bool {
guard let address = validAddress(selector: kAudioHardwareServiceDeviceProperty_VirtualMainVolume,
scope: scope.asPropertyScope) else { return false }

return setProperty(address: address, value: volume)
}

@available(*, deprecated, renamed: "setVirtualMainVolume")
@discardableResult func setVirtualMasterVolume(_ volume: Float32, scope: Scope) -> Bool {
return setVirtualMainVolume(volume, scope: scope)
}

/// The virtual master scalar volume for a given scope.
/// The virtual main scalar volume for a given scope.
///
/// - Parameter scope: A scope.
///
/// - Returns: *(optional)* A `Float32` value with the scalar volume.
func virtualMasterVolume(scope: Scope) -> Float32? {
guard let address = validAddress(selector: kAudioHardwareServiceDeviceProperty_VirtualMasterVolume,
func virtualMainVolume(scope: Scope) -> Float32? {
guard let address = validAddress(selector: kAudioHardwareServiceDeviceProperty_VirtualMainVolume,
scope: scope.asPropertyScope) else { return nil }

return getProperty(address: address)
}

@available(*, deprecated, renamed: "virtualMainVolume")
func virtualMasterVolume(scope: Scope) -> Float32? {
return virtualMainVolume(scope: scope)
}

/// The virtual master volume in decibels for a given scope.
/// The virtual main volume in decibels for a given scope.
///
/// - Parameter scope: A scope.
///
/// - Returns: *(optional)* A `Float32` value with the volume in decibels.
func virtualMasterVolumeInDecibels(scope: Scope) -> Float32? {
func virtualMainVolumeInDecibels(scope: Scope) -> Float32? {
var referenceChannel: UInt32

if canSetVolume(channel: kAudioObjectPropertyElementMaster, scope: scope) {
referenceChannel = kAudioObjectPropertyElementMaster
if canSetVolume(channel: kAudioObjectPropertyElementMain, scope: scope) {
referenceChannel = kAudioObjectPropertyElementMain
} else {
guard let channels = preferredChannelsForStereo(scope: scope) else { return nil }
referenceChannel = channels.0
}

guard let masterVolume = virtualMasterVolume(scope: scope) else { return nil }
guard let mainVolume = virtualMainVolume(scope: scope) else { return nil }

return scalarToDecibels(volume: masterVolume, channel: referenceChannel, scope: scope)
return scalarToDecibels(volume: mainVolume, channel: referenceChannel, scope: scope)
}

@available(*, deprecated, renamed: "virtualMainVolumeInDecibels")
func virtualMasterVolumeInDecibels(scope: Scope) -> Float32? {
return virtualMainVolumeInDecibels(scope: scope)
}

/// The virtual master balance for a given scope.
/// The virtual main balance for a given scope.
///
/// The range is from 0 (all power to the left) to 1 (all power to the right) with the value of 0.5 signifying
/// that the channels have equal power.
///
/// - Parameter scope: A scope.
///
/// - Returns: *(optional)* A `Float32` value with the stereo balance.
func virtualMasterBalance(scope: Scope) -> Float32? {
guard let address = validAddress(selector: kAudioHardwareServiceDeviceProperty_VirtualMasterBalance,
func virtualMainBalance(scope: Scope) -> Float32? {
guard let address = validAddress(selector: kAudioHardwareServiceDeviceProperty_VirtualMainBalance,
scope: scope.asPropertyScope) else { return nil }

return getProperty(address: address)
}

@available(*, deprecated, renamed: "virtualMainBalance")
func virtualMasterBalance(scope: Scope) -> Float32? {
return virtualMainBalance(scope: scope)
}

/// Sets the new virtual master balance for a given scope.
/// Sets the new virtual main balance for a given scope.
///
/// The range is from 0 (all power to the left) to 1 (all power to the right) with the value of 0.5 signifying
/// that the channels have equal power.
///
///setVirtualMainBalance
/// - Parameter value: The new balance.
/// - Parameter scope: A scope.
///
/// - Returns: `true` on success, `false` otherwise.
@discardableResult func setVirtualMasterBalance(_ value: Float32, scope: Scope) -> Bool {
guard let address = validAddress(selector: kAudioHardwareServiceDeviceProperty_VirtualMasterBalance,
@discardableResult func setVirtualMainBalance(_ value: Float32, scope: Scope) -> Bool {
guard let address = validAddress(selector: kAudioHardwareServiceDeviceProperty_VirtualMainBalance,
scope: scope.asPropertyScope) else { return false }

return setProperty(address: address, value: value)
}

@available(*, deprecated, renamed: "setVirtualMainBalance")
@discardableResult func setVirtualMasterBalance(_ value: Float32, scope: Scope) -> Bool {
return setVirtualMainBalance(value, scope: scope)
}
}
2 changes: 1 addition & 1 deletion Sources/SimplyCoreAudio/Public/AudioDevice.swift
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public extension AudioDevice {
let address = AudioObjectPropertyAddress(
mSelector: kAudioHardwarePropertyDeviceForUID,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster
mElement: kAudioObjectPropertyElementMain
)

var deviceID = kAudioObjectUnknown
Expand Down
12 changes: 6 additions & 6 deletions Sources/SimplyCoreAudio/Public/AudioStream.swift
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public final class AudioStream: AudioObject {
var address = AudioObjectPropertyAddress(
mSelector: kAudioStreamPropertyAvailablePhysicalFormats,
mScope: scope.asPropertyScope,
mElement: kAudioObjectPropertyElementMaster
mElement: kAudioObjectPropertyElementMain
)

guard AudioObjectHasProperty(id, &address) else { return nil }
Expand All @@ -168,7 +168,7 @@ public final class AudioStream: AudioObject {
var address = AudioObjectPropertyAddress(
mSelector: kAudioStreamPropertyAvailableVirtualFormats,
mScope: scope.asPropertyScope,
mElement: kAudioObjectPropertyElementMaster
mElement: kAudioObjectPropertyElementMain
)

guard AudioObjectHasProperty(id, &address) else { return nil }
Expand Down Expand Up @@ -274,7 +274,7 @@ public extension AudioStream {
private extension AudioStream {
/// This is an specialized version of `getPropertyData` that only requires passing an `AudioObjectPropertySelector`
/// instead of an `AudioObjectPropertyAddress`. The scope is computed from the stream's `Scope`, and the element
/// is assumed to be `kAudioObjectPropertyElementMaster`.
/// is assumed to be `kAudioObjectPropertyElementMain`.
///
/// Additionally, the property address is validated before calling `getPropertyData`.
///
Expand All @@ -288,7 +288,7 @@ private extension AudioStream {
var address = AudioObjectPropertyAddress(
mSelector: selector,
mScope: scope.asPropertyScope,
mElement: kAudioObjectPropertyElementMaster
mElement: kAudioObjectPropertyElementMain
)

guard AudioObjectHasProperty(id, &address) else { return nil }
Expand All @@ -298,7 +298,7 @@ private extension AudioStream {

/// This is an specialized version of `setPropertyData` that only requires passing an `AudioObjectPropertySelector`
/// instead of an `AudioObjectPropertyAddress`. The scope is computed from the stream's `Scope`, and the element
/// is assumed to be `kAudioObjectPropertyElementMaster`.
/// is assumed to be `kAudioObjectPropertyElementMain`.
///
/// Additionally, the property address is validated before calling `setPropertyData`.
///
Expand All @@ -312,7 +312,7 @@ private extension AudioStream {
var address = AudioObjectPropertyAddress(
mSelector: selector,
mScope: scope.asPropertyScope,
mElement: kAudioObjectPropertyElementMaster
mElement: kAudioObjectPropertyElementMain
)

guard AudioObjectHasProperty(id, &address) else { return nil }
Expand Down
11 changes: 8 additions & 3 deletions Sources/SimplyCoreAudio/Public/Enums/Scope.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,16 @@ public enum Scope {
/// side of an object.
case playthrough

/// The AudioObjectPropertyElement value for properties that apply to the master
/// element or to the entire scope.
/// The AudioObjectPropertyElement value for properties that apply to the main
/// element or to the entire scope. Using deprecated naming
case master

/// The wildcard value for AudioObjectPropertySelectors
case wildcard

/// The AudioObjectPropertyElement value for properties that apply to the main
/// element or to the entire scope.
case main
}

// MARK: - Internal Functions
Expand All @@ -45,7 +49,7 @@ extension Scope {
case .input: return kAudioObjectPropertyScopeInput
case .output: return kAudioObjectPropertyScopeOutput
case .playthrough: return kAudioObjectPropertyScopePlayThrough
case .master: return kAudioObjectPropertyElementMaster
case .main, .master: return kAudioObjectPropertyElementMain
case .wildcard: return kAudioObjectPropertyScopeWildcard
}
}
Expand All @@ -57,6 +61,7 @@ extension Scope {
case kAudioObjectPropertyScopeOutput: return .output
case kAudioObjectPropertyScopePlayThrough: return .playthrough
case kAudioObjectPropertyElementMaster: return .master
case kAudioObjectPropertyElementMain: return .main
case kAudioObjectPropertyScopeWildcard: return .wildcard
default:
// Note, the default is only here to satisfy the switch to be exhaustive.
Expand Down
Loading

0 comments on commit ba8b651

Please sign in to comment.