Skip to content

Instantly share code, notes, and snippets.

@adammw
Created July 17, 2020 22:55
Show Gist options
  • Save adammw/2f910f1fbc6d4f45a1da5f99f4b1be3d to your computer and use it in GitHub Desktop.
Save adammw/2f910f1fbc6d4f45a1da5f99f4b1be3d to your computer and use it in GitHub Desktop.
App to map next track button to input mute toggle
//
// main.swift
// mediakeymute
//
// Created by Adam Malcontenti-Wilson on 16/6/20.
// Copyright © 2020 Adam Malcontenti-Wilson.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
import Foundation
import AVFoundation
import MediaPlayer
import CoreAudio
func getDefaultInputDevice() -> AudioObjectID? {
var propertyAddress = AudioObjectPropertyAddress(mSelector: kAudioHardwarePropertyDefaultInputDevice,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster)
var deviceID:AudioObjectID = AudioObjectID(0)
var size:UInt32 = UInt32(MemoryLayout<AudioObjectID>.size)
let err = AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &propertyAddress, 0, nil, &size, &deviceID)
if err == noErr {
return deviceID
} else {
return nil
}
}
func getDeviceName(deviceID: AudioObjectID) -> String {
var propertyAddress = AudioObjectPropertyAddress(mSelector: kAudioDevicePropertyDeviceName,
mScope: kAudioObjectPropertyScopeGlobal,
mElement: kAudioObjectPropertyElementMaster)
var deviceName = [CChar](repeating:0, count: 64)
var size = UInt32(MemoryLayout<CChar>.size * 64)
let err = AudioObjectGetPropertyData(deviceID, &propertyAddress, 0, nil, &size, &deviceName)
// TODO: handle err
return String.init(cString: deviceName)
}
func getInputMute(deviceID: AudioObjectID) -> Bool {
var propertyAddress = AudioObjectPropertyAddress(mSelector: kAudioDevicePropertyMute,
mScope: kAudioDevicePropertyScopeInput,
mElement: kAudioObjectPropertyElementMaster)
var muteVal = UInt32(0)
var size = UInt32(MemoryLayout<UInt32>.size)
let err = AudioObjectGetPropertyData(deviceID, &propertyAddress, 0, nil, &size, &muteVal)
// TODO: handle err
return muteVal != 0
}
func setInputMute(deviceID: AudioObjectID, mute: Bool) {
var propertyAddress = AudioObjectPropertyAddress(mSelector: kAudioDevicePropertyMute,
mScope: kAudioDevicePropertyScopeInput,
mElement: kAudioObjectPropertyElementMaster)
var muteVal = UInt32(mute ? 1 : 0)
let size = UInt32(MemoryLayout<UInt32>.size)
let err = AudioObjectSetPropertyData(deviceID, &propertyAddress, 0, nil, size, &muteVal)
// TODO: handle err
}
print("Hello, World!")
let deviceID = getDefaultInputDevice()
let deviceName = getDeviceName(deviceID: deviceID!)
print("Controlling device: \(deviceName)")
var mute = getInputMute(deviceID: deviceID!)
var onSoundID = SystemSoundID()
var offSoundID = SystemSoundID()
AudioServicesCreateSystemSoundID(URL.init(fileURLWithPath: "/System/Library/Sounds/Bottle.aiff") as CFURL, &onSoundID)
AudioServicesCreateSystemSoundID(URL.init(fileURLWithPath: "/System/Library/Sounds/Submarine.aiff") as CFURL, &offSoundID)
let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.nextTrackCommand.isEnabled = true;
commandCenter.nextTrackCommand.addTarget(handler: { (e: MPRemoteCommandEvent) -> MPRemoteCommandHandlerStatus in
print("Toggling mute \(mute) -> \(!mute)")
mute = !mute
if mute {
AudioServicesPlayAlertSound(offSoundID)
} else {
AudioServicesPlayAlertSound(onSoundID)
}
setInputMute(deviceID: deviceID!, mute: mute)
return .success
} )
// required to tell macOS we're playing to be able to get commands
MPNowPlayingInfoCenter.default().playbackState = .playing
CFRunLoopRun()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment