Skip to content

Commit

Permalink
Add settings persistence support #2
Browse files Browse the repository at this point in the history
  • Loading branch information
sunnyyoung committed Apr 14, 2019
1 parent f1f7819 commit cb5b0e4
Show file tree
Hide file tree
Showing 2 changed files with 55 additions and 38 deletions.
46 changes: 26 additions & 20 deletions Suohai/SuohaiController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,30 +16,17 @@ class SuohaiController: NSObject {

override init() {
super.init()
self.setupItems()
self.prepareItems()
NotificationCenter.addObserver(observer: self, selector: #selector(reloadMenu), name: .audioDevicesDidChange)
}

deinit {
NotificationCenter.removeObserver(observer: self, name: .audioDevicesDidChange)
}

private func setupItems() {
self.menu = {
let menu = NSMenu()
menu.delegate = self
return menu
}()
self.statusItem = {
let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
item.image = #imageLiteral(resourceName: "StatusItem")
item.target = self
item.menu = self.menu
return item
}()
}

@objc func reloadMenu() {
// Mark: Notification handler
@objc
func reloadMenu() {
let listener = SuohaiListener.shared
self.menu.removeAllItems()
self.menu.addItem(NSMenuItem(title: NSLocalizedString("OutputDevices", comment: "")))
Expand Down Expand Up @@ -73,25 +60,44 @@ class SuohaiController: NSObject {
}

// MARK: Event method
@objc private func selectOutputDeviceAction(_ sender: NSMenuItem) {
@objc
private func selectOutputDeviceAction(_ sender: NSMenuItem) {
let listener = SuohaiListener.shared
guard let device = listener.devices.first(where: {$0.id == UInt32(sender.tag)}) else {
return
}
listener.selectedOutputDeviceID = listener.selectedOutputDeviceID != device.id ? device.id : nil
}

@objc private func selectInputDeviceAction(_ sender: NSMenuItem) {
@objc
private func selectInputDeviceAction(_ sender: NSMenuItem) {
let listener = SuohaiListener.shared
guard let device = listener.devices.first(where: {$0.id == UInt32(sender.tag)}) else {
return
}
listener.selectedInputDeviceID = listener.selectedInputDeviceID != device.id ? device.id : nil
}

@objc private func quitAction(_ sender: NSMenuItem) {
@objc
private func quitAction(_ sender: NSMenuItem) {
NSApplication.shared.terminate(nil)
}

// MARK: UI method
private func prepareItems() {
self.menu = {
let menu = NSMenu()
menu.delegate = self
return menu
}()
self.statusItem = {
let item = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
item.image = #imageLiteral(resourceName: "StatusItem")
item.target = self
item.menu = self.menu
return item
}()
}
}

extension SuohaiController: NSMenuDelegate {
Expand Down
47 changes: 29 additions & 18 deletions Suohai/SuohaiListener.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ enum SuohaiNotification: String {
}
}

struct SuohaiDefaultKeys {
static let audioInputDeviceID = "AudioInputDeviceID"
static let audioOutputDeviceID = "AudioOutputDeviceID"
}

enum AudioDeviceType {
case output
case input
Expand Down Expand Up @@ -54,17 +59,17 @@ struct AudioAddress {
}

struct AudioListener {
static var devices: AudioObjectPropertyListenerProc = {_, _, _, _ in
static var devices: AudioObjectPropertyListenerProc = { _, _, _, _ in
NotificationCenter.post(suohaiNotification: .audioDevicesDidChange)
return 0
}

static var output: AudioObjectPropertyListenerProc = {_, _, _, _ in
static var output: AudioObjectPropertyListenerProc = { _, _, _, _ in
NotificationCenter.post(suohaiNotification: .audioOutputDeviceDidChange)
return 0
}

static var input: AudioObjectPropertyListenerProc = {_, _, _, _ in
static var input: AudioObjectPropertyListenerProc = { _, _, _, _ in
NotificationCenter.post(suohaiNotification: .audioInputDeviceDidChange)
return 0
}
Expand Down Expand Up @@ -123,23 +128,26 @@ class SuohaiListener {

var selectedOutputDeviceID: AudioDeviceID? {
didSet {
guard var deviceID = self.selectedOutputDeviceID else {
return
if var deviceID = self.selectedOutputDeviceID {
self.setOutputDevice(id: &deviceID)
}
self.setOutputDevice(id: &deviceID)
UserDefaults.standard.set(self.selectedOutputDeviceID, forKey: SuohaiDefaultKeys.audioOutputDeviceID)
}
}

var selectedInputDeviceID: AudioDeviceID? {
didSet {
guard var deviceID = self.selectedInputDeviceID else {
return
if var deviceID = self.selectedInputDeviceID {
self.setInputDevice(id: &deviceID)
}
self.setInputDevice(id: &deviceID)
UserDefaults.standard.set(self.selectedInputDeviceID, forKey: SuohaiDefaultKeys.audioInputDeviceID)
}
}

// MARK: Lifecycle
init() {
self.selectedOutputDeviceID = UserDefaults.standard.value(forKey: SuohaiDefaultKeys.audioOutputDeviceID) as? AudioDeviceID
self.selectedInputDeviceID = UserDefaults.standard.value(forKey: SuohaiDefaultKeys.audioInputDeviceID) as? AudioDeviceID
NotificationCenter.addObserver(observer: self, selector: #selector(handleNotification(_:)), name: .audioDevicesDidChange)
NotificationCenter.addObserver(observer: self, selector: #selector(handleNotification(_:)), name: .audioOutputDeviceDidChange)
NotificationCenter.addObserver(observer: self, selector: #selector(handleNotification(_:)), name: .audioInputDeviceDidChange)
Expand All @@ -164,8 +172,19 @@ class SuohaiListener {
AudioObjectRemovePropertyListener(AudioObjectID(kAudioObjectSystemObject), &AudioAddress.inputDevice, AudioListener.input, nil)
}

// MARK: Private method
private func setOutputDevice(id: inout AudioDeviceID) {
AudioObjectSetPropertyData(AudioObjectID(kAudioObjectSystemObject), &AudioAddress.outputDevice, 0, nil, UInt32(MemoryLayout<AudioDeviceID>.size), &id)
}

private func setInputDevice(id: inout AudioDeviceID) {
AudioObjectSetPropertyData(AudioObjectID(kAudioObjectSystemObject), &AudioAddress.inputDevice, 0, nil, UInt32(MemoryLayout<AudioDeviceID>.size), &id)
UserDefaults.standard.set(id, forKey: SuohaiDefaultKeys.audioInputDeviceID)
}

// MARK: Notification handler
@objc private func handleNotification(_ notification: Notification) {
@objc
private func handleNotification(_ notification: Notification) {
if notification.name == SuohaiNotification.audioDevicesDidChange.notificationName {
if !self.devices.contains(where: {$0.id == self.selectedOutputDeviceID}) {
self.selectedOutputDeviceID = nil
Expand All @@ -185,12 +204,4 @@ class SuohaiListener {
self.setInputDevice(id: &deviceID)
}
}

private func setOutputDevice(id: inout AudioDeviceID) {
AudioObjectSetPropertyData(AudioObjectID(kAudioObjectSystemObject), &AudioAddress.outputDevice, 0, nil, UInt32(MemoryLayout<AudioDeviceID>.size), &id)
}

private func setInputDevice(id: inout AudioDeviceID) {
AudioObjectSetPropertyData(AudioObjectID(kAudioObjectSystemObject), &AudioAddress.inputDevice, 0, nil, UInt32(MemoryLayout<AudioDeviceID>.size), &id)
}
}

0 comments on commit cb5b0e4

Please sign in to comment.