diff --git a/jmc.xcodeproj/project.pbxproj b/jmc.xcodeproj/project.pbxproj index 6c3c69f..ad072ec 100644 --- a/jmc.xcodeproj/project.pbxproj +++ b/jmc.xcodeproj/project.pbxproj @@ -121,6 +121,7 @@ 0DC7127C1E2F115A0054ECE6 /* ImportErrorWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DC7127A1E2F115A0054ECE6 /* ImportErrorWindowController.swift */; }; 0DC7127D1E2F115A0054ECE6 /* ImportErrorWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0DC7127B1E2F115A0054ECE6 /* ImportErrorWindowController.xib */; }; 0DCF1D1C1F1D113600240202 /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 0DCF1D191F1D10DC00240202 /* Sparkle.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 0DCF1D251F1D3C6300240202 /* AirPlayDeviceHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0DCF1D241F1D3C6300240202 /* AirPlayDeviceHandler.swift */; }; 0DD0DAE61E53A8EE00807CAC /* flac.rb in Resources */ = {isa = PBXBuildFile; fileRef = 0DD0DAA31E53A8EE00807CAC /* flac.rb */; }; 0DD0DAE71E53A8EE00807CAC /* AUTHORS in Resources */ = {isa = PBXBuildFile; fileRef = 0DD0DAA41E53A8EE00807CAC /* AUTHORS */; }; 0DD0DAE81E53A8EE00807CAC /* flac in Resources */ = {isa = PBXBuildFile; fileRef = 0DD0DAA61E53A8EE00807CAC /* flac */; }; @@ -352,6 +353,7 @@ 0DC7127A1E2F115A0054ECE6 /* ImportErrorWindowController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImportErrorWindowController.swift; path = "Other Windows/ImportErrorWindowController.swift"; sourceTree = ""; }; 0DC7127B1E2F115A0054ECE6 /* ImportErrorWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = ImportErrorWindowController.xib; path = "Other Windows/ImportErrorWindowController.xib"; sourceTree = ""; }; 0DCF1D191F1D10DC00240202 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = "../../Downloads/Sparkle-1.18.0/Sparkle.framework"; sourceTree = ""; }; + 0DCF1D241F1D3C6300240202 /* AirPlayDeviceHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AirPlayDeviceHandler.swift; sourceTree = ""; }; 0DD0DAA31E53A8EE00807CAC /* flac.rb */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.ruby; path = flac.rb; sourceTree = ""; }; 0DD0DAA41E53A8EE00807CAC /* AUTHORS */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = AUTHORS; sourceTree = ""; }; 0DD0DAA61E53A8EE00807CAC /* flac */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.executable"; path = flac; sourceTree = ""; }; @@ -631,6 +633,7 @@ children = ( 0DD0DB0D1E54425800807CAC /* FlacDecoder.swift */, 0D1BDFA41D0F44A70092FBA0 /* AudioModule.swift */, + 0DCF1D241F1D3C6300240202 /* AirPlayDeviceHandler.swift */, 0D606EF51E7B4C21007AE152 /* FileBufferer.swift */, 0D606EF81E7B4DB0007AE152 /* AVAudioFileBufferer.swift */, ); @@ -1299,6 +1302,7 @@ 0DE486831EA579FD009B226B /* AddWatchFolderSheetController.swift in Sources */, 0D76F69B1D24622F00C6E70F /* TagEditorWindow.swift in Sources */, 0D1BDFA51D0F44A70092FBA0 /* AudioModule.swift in Sources */, + 0DCF1D251F1D3C6300240202 /* AirPlayDeviceHandler.swift in Sources */, 0DE957D81EEC5465008CBECF /* OrganizationTemplateBundle+CoreDataProperties.swift in Sources */, 0D8AFE581E6D136D004AC584 /* MediaScannerSheet.swift in Sources */, 0D592A4D1EDF6C8B0054D553 /* TrackView+CoreDataClass.swift in Sources */, diff --git a/jmc.xcodeproj/project.xcworkspace/xcuserdata/johnmoody.xcuserdatad/UserInterfaceState.xcuserstate b/jmc.xcodeproj/project.xcworkspace/xcuserdata/johnmoody.xcuserdatad/UserInterfaceState.xcuserstate index e0a6e57..31c8aa7 100644 Binary files a/jmc.xcodeproj/project.xcworkspace/xcuserdata/johnmoody.xcuserdatad/UserInterfaceState.xcuserstate and b/jmc.xcodeproj/project.xcworkspace/xcuserdata/johnmoody.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/jmc.xcodeproj/xcuserdata/johnmoody.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/jmc.xcodeproj/xcuserdata/johnmoody.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 5cc653e..28b8d41 100644 --- a/jmc.xcodeproj/xcuserdata/johnmoody.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/jmc.xcodeproj/xcuserdata/johnmoody.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -84,11 +84,11 @@ ignoreCount = "0" continueAfterRunningActions = "No" filePath = "jmc/Delegate:Main Window Controller/MainWindowController.swift" - timestampString = "521667626.788035" + timestampString = "522006893.470967" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "328" - endingLineNumber = "328" + startingLineNumber = "332" + endingLineNumber = "332" landmarkName = "tempBreak(_:)" landmarkType = "7"> diff --git a/jmc/AirPlayDeviceHandler.swift b/jmc/AirPlayDeviceHandler.swift new file mode 100644 index 0000000..8556891 --- /dev/null +++ b/jmc/AirPlayDeviceHandler.swift @@ -0,0 +1,71 @@ +// +// AirPlayDeviceHandler.swift +// jmc +// +// Created by John Moody on 7/17/17. +// Copyright © 2017 John Moody. All rights reserved. +// + +import Cocoa +import CoreAudio +import CoreFoundation + +class AirPlayDestination: NSObject { + + var name: String + var id: UInt32 + + init(id: UInt32, airPlayDevice: UInt32) { + self.id = id + var sourceID: UInt32 = 0 + var nameAddr = AudioObjectPropertyAddress(mSelector: kAudioDevicePropertyDataSourceNameForIDCFString, mScope: kAudioObjectPropertyScopeOutput, mElement: kAudioObjectPropertyElementMaster) + var value: CFString = "" as CFString + var audioValueTranslation = AudioValueTranslation(mInputData: &sourceID, mInputDataSize: UInt32(MemoryLayout.size), mOutputData: &value, mOutputDataSize: UInt32(MemoryLayout.size)) + var propsize = UInt32(MemoryLayout.size) + AudioObjectGetPropertyData(airPlayDevice, &nameAddr, 0, nil, &propsize, &audioValueTranslation) + self.name = value as String + } + +} + +class AirPlayDeviceHandler: NSObject { + + var outputs = [AirPlayDestination]() + var device: UInt32 = 0 + + + override init() { + var addr = AudioObjectPropertyAddress(mSelector: kAudioHardwarePropertyDevices, mScope: kAudioObjectPropertyScopeWildcard, mElement: kAudioObjectPropertyElementWildcard) + var propsize: UInt32 = 0 + AudioObjectGetPropertyDataSize(AudioObjectID(kAudioObjectSystemObject), &addr, 0, nil, &propsize) + var deviceIDs = [UInt32](repeating: 0, count: Int(propsize)) + AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &addr, 0, nil, &propsize, &deviceIDs) + + var transportTypeAddr = AudioObjectPropertyAddress(mSelector: kAudioDevicePropertyTransportType, mScope: kAudioObjectPropertyScopeGlobal, mElement: kAudioObjectPropertyElementMaster) + var transportType: UInt32 = 0 + + for device in deviceIDs { + AudioObjectGetPropertyData(device, &transportTypeAddr, 0, nil, &propsize, &transportType) + print(transportType) + if transportType == kAudioDeviceTransportTypeAirPlay { + self.device = device + print("found device") + } + } + super.init() + self.getAirPlayOutputs() + print(outputs) + } + + func getAirPlayOutputs() { + var addr = AudioObjectPropertyAddress(mSelector: kAudioDevicePropertyDataSources, mScope: kAudioDevicePropertyScopeOutput, mElement: kAudioObjectPropertyElementWildcard) + var propsize: UInt32 = 0 + AudioObjectGetPropertyDataSize(self.device, &addr, 0, nil, &propsize) + var sourceIDs = [UInt32](repeating: 0, count: Int(propsize)) + AudioObjectGetPropertyData(self.device, &addr, 0, nil, &propsize, &sourceIDs) + for source in sourceIDs { + outputs.append(AirPlayDestination(id: source, airPlayDevice: self.device)) + } + } + +} diff --git a/jmc/Assets.xcassets/AirPlay.imageset/AirPlayAudioIcon.png b/jmc/Assets.xcassets/AirPlay.imageset/AirPlayAudioIcon.png new file mode 100644 index 0000000..e64d0b3 Binary files /dev/null and b/jmc/Assets.xcassets/AirPlay.imageset/AirPlayAudioIcon.png differ diff --git a/jmc/Assets.xcassets/AirPlay.imageset/Contents.json b/jmc/Assets.xcassets/AirPlay.imageset/Contents.json new file mode 100644 index 0000000..08252fb --- /dev/null +++ b/jmc/Assets.xcassets/AirPlay.imageset/Contents.json @@ -0,0 +1,24 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "AirPlayAudioIcon.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + }, + "properties" : { + "template-rendering-intent" : "template" + } +} \ No newline at end of file diff --git a/jmc/Backend/Audio/AudioModule.swift b/jmc/Backend/Audio/AudioModule.swift index 148581a..1b64e23 100644 --- a/jmc/Backend/Audio/AudioModule.swift +++ b/jmc/Backend/Audio/AudioModule.swift @@ -63,6 +63,7 @@ class AudioModule: NSObject { var fileManager = FileManager.default var upcomingTrackURL: URL? var endOfCurrentTrackFrame: AVAudioFramePosition? + var airplayDeviceHandler: AirPlayDeviceHandler let verbotenFileTypes = ["m4v", "m4p"] @@ -156,6 +157,7 @@ class AudioModule: NSObject { } override init() { + self.airplayDeviceHandler = AirPlayDeviceHandler() super.init() addListenerBlock(audioObjectPropertyListenerBlock, onAudioObjectID: AudioObjectID(bitPattern: kAudioObjectSystemObject), diff --git a/jmc/Delegate:Main Window Controller/AppDelegate.swift b/jmc/Delegate:Main Window Controller/AppDelegate.swift index 888498f..0847c1d 100644 --- a/jmc/Delegate:Main Window Controller/AppDelegate.swift +++ b/jmc/Delegate:Main Window Controller/AppDelegate.swift @@ -37,7 +37,7 @@ class AppDelegate: NSObject, NSApplicationDelegate { mainWindowController!.jumpToCurrentSong() } @IBAction func jumpToSelection(_ sender: Any) { - mainWindowController.jumpToSelection() + mainWindowController?.jumpToSelection() } @IBAction func toggleAlbumArt(_ sender: Any) { mainWindowController?.toggleArtwork(self) diff --git a/jmc/Delegate:Main Window Controller/MainWindowController.swift b/jmc/Delegate:Main Window Controller/MainWindowController.swift index 6329c0d..bbce073 100644 --- a/jmc/Delegate:Main Window Controller/MainWindowController.swift +++ b/jmc/Delegate:Main Window Controller/MainWindowController.swift @@ -355,14 +355,19 @@ class MainWindowController: NSWindowController, NSSearchFieldDelegate, NSWindowD func initAlbumArtwork(for track: Track) { albumArtViewController?.initAlbumArt(track) } + @IBAction func airPlayPressed(_ sender: Any) { + + } @IBAction func toggleArtwork(_ sender: AnyObject) { - if artToggle.state == NSOnState { - UserDefaults.standard.set(true, forKey: DEFAULTS_SHOWS_ARTWORK_STRING) - self.artworkTargetView.isHidden = false - } else { + if self.artworkTargetView.isHidden == false { + artToggle.state = NSOffState UserDefaults.standard.set(false, forKey: DEFAULTS_SHOWS_ARTWORK_STRING) self.artworkTargetView.isHidden = true + } else { + artToggle.state = NSOnState + UserDefaults.standard.set(true, forKey: DEFAULTS_SHOWS_ARTWORK_STRING) + self.artworkTargetView.isHidden = false } } diff --git a/jmc/Delegate:Main Window Controller/MainWindowController.xib b/jmc/Delegate:Main Window Controller/MainWindowController.xib index 2ba7e6a..327c5e2 100644 --- a/jmc/Delegate:Main Window Controller/MainWindowController.xib +++ b/jmc/Delegate:Main Window Controller/MainWindowController.xib @@ -462,11 +462,25 @@ + + @@ -487,6 +501,7 @@ + @@ -521,6 +536,7 @@ + diff --git a/jmc/Other Windows/Library Manager/LibraryManagerViewController.xib b/jmc/Other Windows/Library Manager/LibraryManagerViewController.xib index b0afb64..4486e3e 100644 --- a/jmc/Other Windows/Library Manager/LibraryManagerViewController.xib +++ b/jmc/Other Windows/Library Manager/LibraryManagerViewController.xib @@ -1,8 +1,8 @@ - + - + @@ -13,18 +13,14 @@ - - - - @@ -476,177 +472,6 @@ Gw - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/jmc/Other Windows/PreferencesWindowController.xib b/jmc/Other Windows/PreferencesWindowController.xib index 7261f18..76890d3 100644 --- a/jmc/Other Windows/PreferencesWindowController.xib +++ b/jmc/Other Windows/PreferencesWindowController.xib @@ -221,6 +221,12 @@ + + + + + + @@ -343,11 +349,13 @@ + + @@ -363,6 +371,7 @@ +