├── README.md └── workflow ├── 1450496C-74BC-4EDE-930B-ADC6027C5449.png ├── 5F417B1B-FC67-40CE-8084-167913379DDE.png ├── 692C13A0-ADC1-4E71-8FA4-0157FF14C88F.png ├── 7155F88D-55F6-4608-BC2E-554BA0780537.png ├── 71AAE21C-028C-45CE-AB44-1378572652A9.png ├── 864A20DF-C5E2-444E-B084-9CD126BED7DF.png ├── 9F22BA12-18B5-4FA5-B429-12DB07DBDC90.png ├── A0CE40D8-D874-48D7-903B-0C91A6B2F7DC.png ├── AD6FA975-C31E-4D56-BF48-EBBC634EB89E.png ├── AFF1A33C-2AE0-4CA1-8B00-04BB87A5F7FE.png ├── B066EEAB-4F3C-4516-9F00-E8FD7A5439B6.png ├── C0967D8A-BEF8-44B5-BF2A-06BD127C8D73.png ├── CBBA9D5E-DB01-490E-9C0F-F33A07F09E3A.png ├── List Filter Images ├── 3ab9aedf8fbd94a12254709139ffcee0a288338b.png └── b171fc8163f973fcfe9f43d328811fe1096dcebe.png ├── _remote ├── images │ ├── items │ │ ├── 40AD86DC-2F23-492C-B2D1-08929C492E0B.png │ │ ├── 7A4C66E5-7DBE-4D49-B3F9-7B48997E5DE4.png │ │ ├── 87ADC83C-BEC2-4413-9593-B84836DF334E.png │ │ ├── 9EE11D58-1E5E-4998-9244-816938F5E03C.png │ │ ├── AC51B392-A245-467B-BE86-56F7A911784C.png │ │ ├── C966F8A3-DEF0-4959-AFB3-02D7591DDC07.png │ │ ├── DD79A2C0-84C6-4BBF-BF3E-F30DA82567A2.png │ │ └── E689AAFE-047D-4F33-AF0F-F4C0162707BA.png │ └── pages │ │ └── 1087F40F-223B-4FD8-9D7E-3E3AFBBFCB28.png └── pages │ ├── C7966D69-3C00-4D1C-8C90-FC19D2DEE491.data │ └── pages.data ├── icon.png ├── icons ├── input.png ├── input_selected.png ├── output.png └── output_selected.png ├── info.plist └── main.swift /README.md: -------------------------------------------------------------------------------- 1 | # Alfred App Audio Switcher Workflow 2 | This is a workflow for [Alfred](https://alfred.app/). 3 | 4 | ## About the Workflow 5 | This workflow supports quickly switching sound input and output devices. 6 | 7 | It offers hotkeys to quickly switch between three input favorites and output favorites. 8 | You can also use a single hotkey to rotate among the favorites in sequence. 9 | Those can also be triggered using Alfred Remote. 10 | 11 | ### Listing Devices 12 | Once installed, use the `fetchaudiodevices` command in Alfred. Once you have selected either "Outputs" or "Inputs", 13 | the workflow will copy a list of devices to the Clipboard. This is a convenience feature to support filling the 14 | *Ignorelist*, *Output Favorites* and *Input Favorites*. (See below) 15 | 16 | ### Parameter Examples 17 | 18 | #### Ignorelist 19 | The value 20 | ``` 21 | External Headphones 22 | iPhone Microphone 23 | ``` 24 | causes both listed devices not to be listed when selecting inputs or outputs. 25 | 26 | 27 | #### Output Favorites 28 | The value 29 | ``` 30 | MacBook Pro Speakers 31 | RØDE Connect Virtual 32 | External Screen 33 | ``` 34 | means the following: 35 | - *⌘ + F1* will select MacBook Pro Speakers. 36 | - *⌘ + F2* will select RØDE Connect Virtual. 37 | - *⌘ + F3* will select External Screen. 38 | 39 | #### Input Favorites 40 | The value 41 | ``` 42 | MacBook Pro Microphone 43 | RØDE Connect Stream 44 | ``` 45 | means the following: 46 | - *⌥ + F1* will select MacBook Pro Microphone. 47 | - *⌥ + F2* will select RØDE Connect Stream. 48 | - *⌥ + F3* will have no effect. 49 | 50 | ## Like this Workflow? 51 | [!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://buymeacoffee.com/tobimende) 52 | -------------------------------------------------------------------------------- /workflow/1450496C-74BC-4EDE-930B-ADC6027C5449.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/1450496C-74BC-4EDE-930B-ADC6027C5449.png -------------------------------------------------------------------------------- /workflow/5F417B1B-FC67-40CE-8084-167913379DDE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/5F417B1B-FC67-40CE-8084-167913379DDE.png -------------------------------------------------------------------------------- /workflow/692C13A0-ADC1-4E71-8FA4-0157FF14C88F.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/692C13A0-ADC1-4E71-8FA4-0157FF14C88F.png -------------------------------------------------------------------------------- /workflow/7155F88D-55F6-4608-BC2E-554BA0780537.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/7155F88D-55F6-4608-BC2E-554BA0780537.png -------------------------------------------------------------------------------- /workflow/71AAE21C-028C-45CE-AB44-1378572652A9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/71AAE21C-028C-45CE-AB44-1378572652A9.png -------------------------------------------------------------------------------- /workflow/864A20DF-C5E2-444E-B084-9CD126BED7DF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/864A20DF-C5E2-444E-B084-9CD126BED7DF.png -------------------------------------------------------------------------------- /workflow/9F22BA12-18B5-4FA5-B429-12DB07DBDC90.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/9F22BA12-18B5-4FA5-B429-12DB07DBDC90.png -------------------------------------------------------------------------------- /workflow/A0CE40D8-D874-48D7-903B-0C91A6B2F7DC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/A0CE40D8-D874-48D7-903B-0C91A6B2F7DC.png -------------------------------------------------------------------------------- /workflow/AD6FA975-C31E-4D56-BF48-EBBC634EB89E.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/AD6FA975-C31E-4D56-BF48-EBBC634EB89E.png -------------------------------------------------------------------------------- /workflow/AFF1A33C-2AE0-4CA1-8B00-04BB87A5F7FE.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/AFF1A33C-2AE0-4CA1-8B00-04BB87A5F7FE.png -------------------------------------------------------------------------------- /workflow/B066EEAB-4F3C-4516-9F00-E8FD7A5439B6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/B066EEAB-4F3C-4516-9F00-E8FD7A5439B6.png -------------------------------------------------------------------------------- /workflow/C0967D8A-BEF8-44B5-BF2A-06BD127C8D73.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/C0967D8A-BEF8-44B5-BF2A-06BD127C8D73.png -------------------------------------------------------------------------------- /workflow/CBBA9D5E-DB01-490E-9C0F-F33A07F09E3A.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/CBBA9D5E-DB01-490E-9C0F-F33A07F09E3A.png -------------------------------------------------------------------------------- /workflow/List Filter Images/3ab9aedf8fbd94a12254709139ffcee0a288338b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/List Filter Images/3ab9aedf8fbd94a12254709139ffcee0a288338b.png -------------------------------------------------------------------------------- /workflow/List Filter Images/b171fc8163f973fcfe9f43d328811fe1096dcebe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/List Filter Images/b171fc8163f973fcfe9f43d328811fe1096dcebe.png -------------------------------------------------------------------------------- /workflow/_remote/images/items/40AD86DC-2F23-492C-B2D1-08929C492E0B.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/_remote/images/items/40AD86DC-2F23-492C-B2D1-08929C492E0B.png -------------------------------------------------------------------------------- /workflow/_remote/images/items/7A4C66E5-7DBE-4D49-B3F9-7B48997E5DE4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/_remote/images/items/7A4C66E5-7DBE-4D49-B3F9-7B48997E5DE4.png -------------------------------------------------------------------------------- /workflow/_remote/images/items/87ADC83C-BEC2-4413-9593-B84836DF334E.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/_remote/images/items/87ADC83C-BEC2-4413-9593-B84836DF334E.png -------------------------------------------------------------------------------- /workflow/_remote/images/items/9EE11D58-1E5E-4998-9244-816938F5E03C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/_remote/images/items/9EE11D58-1E5E-4998-9244-816938F5E03C.png -------------------------------------------------------------------------------- /workflow/_remote/images/items/AC51B392-A245-467B-BE86-56F7A911784C.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/_remote/images/items/AC51B392-A245-467B-BE86-56F7A911784C.png -------------------------------------------------------------------------------- /workflow/_remote/images/items/C966F8A3-DEF0-4959-AFB3-02D7591DDC07.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/_remote/images/items/C966F8A3-DEF0-4959-AFB3-02D7591DDC07.png -------------------------------------------------------------------------------- /workflow/_remote/images/items/DD79A2C0-84C6-4BBF-BF3E-F30DA82567A2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/_remote/images/items/DD79A2C0-84C6-4BBF-BF3E-F30DA82567A2.png -------------------------------------------------------------------------------- /workflow/_remote/images/items/E689AAFE-047D-4F33-AF0F-F4C0162707BA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/_remote/images/items/E689AAFE-047D-4F33-AF0F-F4C0162707BA.png -------------------------------------------------------------------------------- /workflow/_remote/images/pages/1087F40F-223B-4FD8-9D7E-3E3AFBBFCB28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/_remote/images/pages/1087F40F-223B-4FD8-9D7E-3E3AFBBFCB28.png -------------------------------------------------------------------------------- /workflow/_remote/pages/C7966D69-3C00-4D1C-8C90-FC19D2DEE491.data: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | gridsize 6 | 4 7 | hidelabels 8 | 9 | iconid 10 | 1087F40F-223B-4FD8-9D7E-3E3AFBBFCB28 11 | iconisuserspecified 12 | 13 | items 14 | 15 | 16 | actionconfig 17 | 18 | autoworkflowuid 19 | 20 | confirm 21 | 22 | triggerid 23 | io.mende.audioswitcher.out 24 | 25 | actionuid 26 | remote.alfred.runworkflow 27 | buttoniconid 28 | 40AD86DC-2F23-492C-B2D1-08929C492E0B 29 | buttonlabel 30 | Select Output 31 | itemuid 32 | 005EAC2D-B938-4C5C-8561-F50457AB0B50 33 | 34 | 35 | actionconfig 36 | 37 | autoworkflowuid 38 | 39 | confirm 40 | 41 | triggerid 42 | io.mende.audioswitcher.in 43 | 44 | actionuid 45 | remote.alfred.runworkflow 46 | buttoniconid 47 | 87ADC83C-BEC2-4413-9593-B84836DF334E 48 | buttonlabel 49 | Select Input 50 | itemuid 51 | 75670CDA-C99C-4766-805C-60F5BBA8D1A8 52 | 53 | 54 | 55 | 56 | actionconfig 57 | 58 | autoworkflowuid 59 | 60 | confirm 61 | 62 | triggerid 63 | io.mende.audioswitcher.out1 64 | 65 | actionuid 66 | remote.alfred.runworkflow 67 | buttoniconid 68 | DD79A2C0-84C6-4BBF-BF3E-F30DA82567A2 69 | buttonlabel 70 | Select Output 1 71 | itemuid 72 | 6E42C8C1-CCC5-4E1A-92A6-70DE3109840D 73 | 74 | 75 | actionconfig 76 | 77 | autoworkflowuid 78 | 79 | confirm 80 | 81 | triggerid 82 | io.mende.audioswitcher.out2 83 | 84 | actionuid 85 | remote.alfred.runworkflow 86 | buttoniconid 87 | E689AAFE-047D-4F33-AF0F-F4C0162707BA 88 | buttonlabel 89 | Select Output 2 90 | itemuid 91 | ECF88431-BA01-4627-B690-EC1C5698DB22 92 | 93 | 94 | actionconfig 95 | 96 | autoworkflowuid 97 | 98 | confirm 99 | 100 | triggerid 101 | io.mende.audioswitcher.out3 102 | 103 | actionuid 104 | remote.alfred.runworkflow 105 | buttoniconid 106 | C966F8A3-DEF0-4959-AFB3-02D7591DDC07 107 | buttonlabel 108 | Select Output 3 109 | itemuid 110 | 21C9200A-0FC8-4E1E-B75B-F2162281402A 111 | 112 | 113 | 114 | actionconfig 115 | 116 | autoworkflowuid 117 | 118 | confirm 119 | 120 | triggerid 121 | io.mende.audioswitcher.in1 122 | 123 | actionuid 124 | remote.alfred.runworkflow 125 | buttoniconid 126 | 9EE11D58-1E5E-4998-9244-816938F5E03C 127 | buttonlabel 128 | Select Input 1 129 | itemuid 130 | 6A6B50F8-B17E-4129-B736-C259BE1B6312 131 | 132 | 133 | actionconfig 134 | 135 | autoworkflowuid 136 | 137 | confirm 138 | 139 | triggerid 140 | io.mende.audioswitcher.in2 141 | 142 | actionuid 143 | remote.alfred.runworkflow 144 | buttoniconid 145 | 7A4C66E5-7DBE-4D49-B3F9-7B48997E5DE4 146 | buttonlabel 147 | Select Input 2 148 | itemuid 149 | 6FEAAFA1-D37B-4A92-916A-81840C79F805 150 | 151 | 152 | actionconfig 153 | 154 | autoworkflowuid 155 | 156 | confirm 157 | 158 | triggerid 159 | io.mende.audioswitcher.in3 160 | 161 | actionuid 162 | remote.alfred.runworkflow 163 | buttoniconid 164 | AC51B392-A245-467B-BE86-56F7A911784C 165 | buttonlabel 166 | Select Input 3 167 | itemuid 168 | A36A4EAA-DDFC-458B-B32F-855B916722F9 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | itemsall 177 | 178 | 179 | actionconfig 180 | 181 | autoworkflowuid 182 | 183 | confirm 184 | 185 | triggerid 186 | io.mende.audioswitcher.out 187 | 188 | actionuid 189 | remote.alfred.runworkflow 190 | buttoniconid 191 | 40AD86DC-2F23-492C-B2D1-08929C492E0B 192 | buttonlabel 193 | Select Output 194 | itemuid 195 | 005EAC2D-B938-4C5C-8561-F50457AB0B50 196 | 197 | 198 | actionconfig 199 | 200 | autoworkflowuid 201 | 202 | confirm 203 | 204 | triggerid 205 | io.mende.audioswitcher.in 206 | 207 | actionuid 208 | remote.alfred.runworkflow 209 | buttoniconid 210 | 87ADC83C-BEC2-4413-9593-B84836DF334E 211 | buttonlabel 212 | Select Input 213 | itemuid 214 | 75670CDA-C99C-4766-805C-60F5BBA8D1A8 215 | 216 | 217 | 218 | 219 | actionconfig 220 | 221 | autoworkflowuid 222 | 223 | confirm 224 | 225 | triggerid 226 | io.mende.audioswitcher.out1 227 | 228 | actionuid 229 | remote.alfred.runworkflow 230 | buttoniconid 231 | DD79A2C0-84C6-4BBF-BF3E-F30DA82567A2 232 | buttonlabel 233 | Select Output 1 234 | itemuid 235 | 6E42C8C1-CCC5-4E1A-92A6-70DE3109840D 236 | 237 | 238 | actionconfig 239 | 240 | autoworkflowuid 241 | 242 | confirm 243 | 244 | triggerid 245 | io.mende.audioswitcher.out2 246 | 247 | actionuid 248 | remote.alfred.runworkflow 249 | buttoniconid 250 | E689AAFE-047D-4F33-AF0F-F4C0162707BA 251 | buttonlabel 252 | Select Output 2 253 | itemuid 254 | ECF88431-BA01-4627-B690-EC1C5698DB22 255 | 256 | 257 | actionconfig 258 | 259 | autoworkflowuid 260 | 261 | confirm 262 | 263 | triggerid 264 | io.mende.audioswitcher.out3 265 | 266 | actionuid 267 | remote.alfred.runworkflow 268 | buttoniconid 269 | C966F8A3-DEF0-4959-AFB3-02D7591DDC07 270 | buttonlabel 271 | Select Output 3 272 | itemuid 273 | 21C9200A-0FC8-4E1E-B75B-F2162281402A 274 | 275 | 276 | 277 | actionconfig 278 | 279 | autoworkflowuid 280 | 281 | confirm 282 | 283 | triggerid 284 | io.mende.audioswitcher.in1 285 | 286 | actionuid 287 | remote.alfred.runworkflow 288 | buttoniconid 289 | 9EE11D58-1E5E-4998-9244-816938F5E03C 290 | buttonlabel 291 | Select Input 1 292 | itemuid 293 | 6A6B50F8-B17E-4129-B736-C259BE1B6312 294 | 295 | 296 | actionconfig 297 | 298 | autoworkflowuid 299 | 300 | confirm 301 | 302 | triggerid 303 | io.mende.audioswitcher.in2 304 | 305 | actionuid 306 | remote.alfred.runworkflow 307 | buttoniconid 308 | 7A4C66E5-7DBE-4D49-B3F9-7B48997E5DE4 309 | buttonlabel 310 | Select Input 2 311 | itemuid 312 | 6FEAAFA1-D37B-4A92-916A-81840C79F805 313 | 314 | 315 | actionconfig 316 | 317 | autoworkflowuid 318 | 319 | confirm 320 | 321 | triggerid 322 | io.mende.audioswitcher.in3 323 | 324 | actionuid 325 | remote.alfred.runworkflow 326 | buttoniconid 327 | AC51B392-A245-467B-BE86-56F7A911784C 328 | buttonlabel 329 | Select Input 3 330 | itemuid 331 | A36A4EAA-DDFC-458B-B32F-855B916722F9 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | subtitle 360 | Switching inputs and outputs 361 | title 362 | Audio Switcher 363 | 364 | 365 | -------------------------------------------------------------------------------- /workflow/_remote/pages/pages.data: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | pages 6 | 7 | C7966D69-3C00-4D1C-8C90-FC19D2DEE491 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /workflow/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/icon.png -------------------------------------------------------------------------------- /workflow/icons/input.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/icons/input.png -------------------------------------------------------------------------------- /workflow/icons/input_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/icons/input_selected.png -------------------------------------------------------------------------------- /workflow/icons/output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/icons/output.png -------------------------------------------------------------------------------- /workflow/icons/output_selected.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TobiasMende/alfred-audio-switcher/ea1993a5a654515e2a412763fc70242e96ea8141/workflow/icons/output_selected.png -------------------------------------------------------------------------------- /workflow/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bundleid 6 | io.mende.alfredapp-audioswitcher 7 | category 8 | Tools 9 | connections 10 | 11 | 00704246-FE25-4B27-86E9-2EB6EDF00D67 12 | 13 | 14 | destinationuid 15 | 09EBB07A-0EF4-4CDB-96E1-7A4EDC0561F4 16 | modifiers 17 | 0 18 | modifiersubtext 19 | 20 | vitoclose 21 | 22 | 23 | 24 | 01427E94-9408-4123-A9BC-DF6185AB3A85 25 | 26 | 27 | destinationuid 28 | 39B059B1-CD01-4C2D-8907-1E2F9262CD04 29 | modifiers 30 | 0 31 | modifiersubtext 32 | 33 | vitoclose 34 | 35 | 36 | 37 | 1450496C-74BC-4EDE-930B-ADC6027C5449 38 | 39 | 40 | destinationuid 41 | FCE19CD4-E3AE-4361-8B59-F357914A629C 42 | modifiers 43 | 0 44 | modifiersubtext 45 | 46 | vitoclose 47 | 48 | 49 | 50 | 1AF283DE-8EDC-4006-AD54-91F4C226E5C9 51 | 52 | 53 | destinationuid 54 | BA2ED978-7611-4D11-9EA1-8A0A1E275FD0 55 | modifiers 56 | 0 57 | modifiersubtext 58 | 59 | vitoclose 60 | 61 | 62 | 63 | 3AE8EB58-5F7D-49B6-98C1-4BAE5E79FC2E 64 | 65 | 66 | destinationuid 67 | 39B059B1-CD01-4C2D-8907-1E2F9262CD04 68 | modifiers 69 | 0 70 | modifiersubtext 71 | 72 | vitoclose 73 | 74 | 75 | 76 | 3B2897E7-E242-4504-A297-602265B0011F 77 | 78 | 79 | destinationuid 80 | 39B059B1-CD01-4C2D-8907-1E2F9262CD04 81 | modifiers 82 | 0 83 | modifiersubtext 84 | 85 | vitoclose 86 | 87 | 88 | 89 | 5F417B1B-FC67-40CE-8084-167913379DDE 90 | 91 | 92 | destinationuid 93 | BA2ED978-7611-4D11-9EA1-8A0A1E275FD0 94 | modifiers 95 | 0 96 | modifiersubtext 97 | 98 | vitoclose 99 | 100 | 101 | 102 | 692C13A0-ADC1-4E71-8FA4-0157FF14C88F 103 | 104 | 105 | destinationuid 106 | 01427E94-9408-4123-A9BC-DF6185AB3A85 107 | modifiers 108 | 0 109 | modifiersubtext 110 | 111 | vitoclose 112 | 113 | 114 | 115 | 6CDEB1A2-F0E3-4C17-955A-7AA171D8C899 116 | 117 | 118 | destinationuid 119 | 3B2897E7-E242-4504-A297-602265B0011F 120 | modifiers 121 | 0 122 | modifiersubtext 123 | 124 | vitoclose 125 | 126 | 127 | 128 | 6EEBB03A-5A12-4883-BEF4-2DAC11BF0FC0 129 | 130 | 131 | destinationuid 132 | 3B2897E7-E242-4504-A297-602265B0011F 133 | modifiers 134 | 0 135 | modifiersubtext 136 | 137 | vitoclose 138 | 139 | 140 | 141 | 7155F88D-55F6-4608-BC2E-554BA0780537 142 | 143 | 144 | destinationuid 145 | F6A49F45-6CB5-4CDF-BB3E-79B7715ACA0F 146 | modifiers 147 | 0 148 | modifiersubtext 149 | 150 | vitoclose 151 | 152 | 153 | 154 | 71AAE21C-028C-45CE-AB44-1378572652A9 155 | 156 | 157 | destinationuid 158 | 1450496C-74BC-4EDE-930B-ADC6027C5449 159 | modifiers 160 | 0 161 | modifiersubtext 162 | 163 | vitoclose 164 | 165 | 166 | 167 | 7A1840A7-3844-4206-9B9E-B0602C41361E 168 | 169 | 170 | destinationuid 171 | F6A49F45-6CB5-4CDF-BB3E-79B7715ACA0F 172 | modifiers 173 | 0 174 | modifiersubtext 175 | 176 | vitoclose 177 | 178 | 179 | 180 | 82D538CB-521F-4F59-99A5-91AFC57E3CF3 181 | 182 | 183 | destinationuid 184 | F6A49F45-6CB5-4CDF-BB3E-79B7715ACA0F 185 | modifiers 186 | 0 187 | modifiersubtext 188 | 189 | vitoclose 190 | 191 | 192 | 193 | 86324099-F14A-4ADC-9C93-992F23163004 194 | 195 | 196 | destinationuid 197 | 01427E94-9408-4123-A9BC-DF6185AB3A85 198 | modifiers 199 | 0 200 | modifiersubtext 201 | 202 | vitoclose 203 | 204 | 205 | 206 | 864A20DF-C5E2-444E-B084-9CD126BED7DF 207 | 208 | 209 | destinationuid 210 | 3B2897E7-E242-4504-A297-602265B0011F 211 | modifiers 212 | 0 213 | modifiersubtext 214 | 215 | vitoclose 216 | 217 | 218 | 219 | 9D6F6749-4476-48A0-BF59-8B80656B1F51 220 | 221 | 222 | destinationuid 223 | 3B2897E7-E242-4504-A297-602265B0011F 224 | modifiers 225 | 0 226 | modifiersubtext 227 | 228 | vitoclose 229 | 230 | 231 | 232 | 9F22BA12-18B5-4FA5-B429-12DB07DBDC90 233 | 234 | 235 | destinationuid 236 | C46B89C0-5C32-4E45-84C4-714DAA27F2BD 237 | modifiers 238 | 0 239 | modifiersubtext 240 | 241 | vitoclose 242 | 243 | 244 | 245 | A0CE40D8-D874-48D7-903B-0C91A6B2F7DC 246 | 247 | 248 | destinationuid 249 | 3B2897E7-E242-4504-A297-602265B0011F 250 | modifiers 251 | 0 252 | modifiersubtext 253 | 254 | vitoclose 255 | 256 | 257 | 258 | A3266036-2FB4-4E74-B315-F9951154B58F 259 | 260 | 261 | destinationuid 262 | F6A49F45-6CB5-4CDF-BB3E-79B7715ACA0F 263 | modifiers 264 | 0 265 | modifiersubtext 266 | 267 | vitoclose 268 | 269 | 270 | 271 | AD6FA975-C31E-4D56-BF48-EBBC634EB89E 272 | 273 | 274 | destinationuid 275 | 3B2897E7-E242-4504-A297-602265B0011F 276 | modifiers 277 | 0 278 | modifiersubtext 279 | 280 | vitoclose 281 | 282 | 283 | 284 | AFF1A33C-2AE0-4CA1-8B00-04BB87A5F7FE 285 | 286 | 287 | destinationuid 288 | B066EEAB-4F3C-4516-9F00-E8FD7A5439B6 289 | modifiers 290 | 0 291 | modifiersubtext 292 | 293 | vitoclose 294 | 295 | 296 | 297 | B066EEAB-4F3C-4516-9F00-E8FD7A5439B6 298 | 299 | 300 | destinationuid 301 | 3AE8EB58-5F7D-49B6-98C1-4BAE5E79FC2E 302 | modifiers 303 | 0 304 | modifiersubtext 305 | 306 | vitoclose 307 | 308 | 309 | 310 | BA2ED978-7611-4D11-9EA1-8A0A1E275FD0 311 | 312 | 313 | destinationuid 314 | 39B059B1-CD01-4C2D-8907-1E2F9262CD04 315 | modifiers 316 | 0 317 | modifiersubtext 318 | 319 | vitoclose 320 | 321 | 322 | 323 | C0967D8A-BEF8-44B5-BF2A-06BD127C8D73 324 | 325 | 326 | destinationuid 327 | F6A49F45-6CB5-4CDF-BB3E-79B7715ACA0F 328 | modifiers 329 | 0 330 | modifiersubtext 331 | 332 | vitoclose 333 | 334 | 335 | 336 | C46B89C0-5C32-4E45-84C4-714DAA27F2BD 337 | 338 | 339 | destinationuid 340 | 00704246-FE25-4B27-86E9-2EB6EDF00D67 341 | modifiers 342 | 0 343 | modifiersubtext 344 | 345 | vitoclose 346 | 347 | 348 | 349 | CBBA9D5E-DB01-490E-9C0F-F33A07F09E3A 350 | 351 | 352 | destinationuid 353 | F6A49F45-6CB5-4CDF-BB3E-79B7715ACA0F 354 | modifiers 355 | 0 356 | modifiersubtext 357 | 358 | vitoclose 359 | 360 | 361 | 362 | F6A49F45-6CB5-4CDF-BB3E-79B7715ACA0F 363 | 364 | 365 | destinationuid 366 | 39B059B1-CD01-4C2D-8907-1E2F9262CD04 367 | modifiers 368 | 0 369 | modifiersubtext 370 | 371 | vitoclose 372 | 373 | 374 | 375 | FCE19CD4-E3AE-4361-8B59-F357914A629C 376 | 377 | 378 | destinationuid 379 | 39B059B1-CD01-4C2D-8907-1E2F9262CD04 380 | modifiers 381 | 0 382 | modifiersubtext 383 | 384 | vitoclose 385 | 386 | 387 | 388 | 389 | createdby 390 | Tobias Mende 391 | description 392 | Swiftly switch audio output and input devices 393 | disabled 394 | 395 | name 396 | Audio Switcher 397 | objects 398 | 399 | 400 | config 401 | 402 | concurrently 403 | 404 | escaping 405 | 102 406 | script 407 | ./main.swift switch_by_id output $1 408 | scriptargtype 409 | 1 410 | scriptfile 411 | 412 | type 413 | 11 414 | 415 | type 416 | alfred.workflow.action.script 417 | uid 418 | 3AE8EB58-5F7D-49B6-98C1-4BAE5E79FC2E 419 | version 420 | 2 421 | 422 | 423 | config 424 | 425 | alfredfiltersresults 426 | 427 | alfredfiltersresultsmatchmode 428 | 2 429 | argumenttreatemptyqueryasnil 430 | 431 | argumenttrimmode 432 | 0 433 | argumenttype 434 | 1 435 | escaping 436 | 102 437 | keyword 438 | {var:output_keyword} 439 | queuedelaycustom 440 | 3 441 | queuedelayimmediatelyinitially 442 | 443 | queuedelaymode 444 | 0 445 | queuemode 446 | 1 447 | runningsubtext 448 | Please Wait 449 | script 450 | ./main.swift list output "$ignorelist" "$outputs" 451 | scriptargtype 452 | 1 453 | scriptfile 454 | 455 | subtext 456 | Select an Output Device 457 | title 458 | Audio Outputs 459 | type 460 | 11 461 | withspace 462 | 463 | 464 | type 465 | alfred.workflow.input.scriptfilter 466 | uid 467 | B066EEAB-4F3C-4516-9F00-E8FD7A5439B6 468 | version 469 | 3 470 | 471 | 472 | config 473 | 474 | argument 475 | 476 | argumenttype 477 | 0 478 | triggerid 479 | io.mende.audioswitcher.out 480 | triggername 481 | Select Output 482 | workflowonly 483 | 484 | 485 | type 486 | alfred.workflow.trigger.remote 487 | uid 488 | AFF1A33C-2AE0-4CA1-8B00-04BB87A5F7FE 489 | version 490 | 1 491 | 492 | 493 | config 494 | 495 | argument 496 | 497 | argumenttype 498 | 0 499 | triggerid 500 | io.mende.audioswitcher.in 501 | triggername 502 | Select Input 503 | workflowonly 504 | 505 | 506 | type 507 | alfred.workflow.trigger.remote 508 | uid 509 | 71AAE21C-028C-45CE-AB44-1378572652A9 510 | version 511 | 1 512 | 513 | 514 | config 515 | 516 | alfredfiltersresults 517 | 518 | alfredfiltersresultsmatchmode 519 | 2 520 | argumenttreatemptyqueryasnil 521 | 522 | argumenttrimmode 523 | 0 524 | argumenttype 525 | 1 526 | escaping 527 | 102 528 | keyword 529 | {var:input_keyword} 530 | queuedelaycustom 531 | 3 532 | queuedelayimmediatelyinitially 533 | 534 | queuedelaymode 535 | 0 536 | queuemode 537 | 1 538 | runningsubtext 539 | Please Wait 540 | script 541 | ./main.swift list input "$ignorelist" "$inputs" 542 | scriptargtype 543 | 1 544 | scriptfile 545 | 546 | subtext 547 | Select an Input Device 548 | title 549 | Audio Inputs 550 | type 551 | 11 552 | withspace 553 | 554 | 555 | type 556 | alfred.workflow.input.scriptfilter 557 | uid 558 | 1450496C-74BC-4EDE-930B-ADC6027C5449 559 | version 560 | 3 561 | 562 | 563 | config 564 | 565 | concurrently 566 | 567 | escaping 568 | 68 569 | script 570 | ./main.swift switch_by_id input $1 571 | scriptargtype 572 | 1 573 | scriptfile 574 | 575 | type 576 | 11 577 | 578 | type 579 | alfred.workflow.action.script 580 | uid 581 | FCE19CD4-E3AE-4361-8B59-F357914A629C 582 | version 583 | 2 584 | 585 | 586 | config 587 | 588 | argument 589 | 0 590 | argumenttype 591 | 3 592 | triggerid 593 | io.mende.audioswitcher.out1 594 | triggername 595 | Select Output 1 596 | workflowonly 597 | 598 | 599 | type 600 | alfred.workflow.trigger.remote 601 | uid 602 | AD6FA975-C31E-4D56-BF48-EBBC634EB89E 603 | version 604 | 1 605 | 606 | 607 | config 608 | 609 | action 610 | 0 611 | argument 612 | 3 613 | argumenttext 614 | 0 615 | focusedappvariable 616 | 617 | focusedappvariablename 618 | 619 | hotkey 620 | 122 621 | hotmod 622 | 9437184 623 | hotstring 624 | F1 625 | leftcursor 626 | 627 | modsmode 628 | 0 629 | relatedAppsMode 630 | 0 631 | 632 | type 633 | alfred.workflow.trigger.hotkey 634 | uid 635 | 6CDEB1A2-F0E3-4C17-955A-7AA171D8C899 636 | version 637 | 2 638 | 639 | 640 | config 641 | 642 | argument 643 | 1 644 | argumenttype 645 | 3 646 | triggerid 647 | io.mende.audioswitcher.out2 648 | triggername 649 | Select Output 2 650 | workflowonly 651 | 652 | 653 | type 654 | alfred.workflow.trigger.remote 655 | uid 656 | 864A20DF-C5E2-444E-B084-9CD126BED7DF 657 | version 658 | 1 659 | 660 | 661 | config 662 | 663 | concurrently 664 | 665 | escaping 666 | 68 667 | script 668 | ./main.swift switch_by_name output $1 "$outputs" 669 | scriptargtype 670 | 1 671 | scriptfile 672 | 673 | type 674 | 11 675 | 676 | type 677 | alfred.workflow.action.script 678 | uid 679 | 3B2897E7-E242-4504-A297-602265B0011F 680 | version 681 | 2 682 | 683 | 684 | config 685 | 686 | action 687 | 0 688 | argument 689 | 3 690 | argumenttext 691 | 1 692 | focusedappvariable 693 | 694 | focusedappvariablename 695 | 696 | hotkey 697 | 120 698 | hotmod 699 | 9437184 700 | hotstring 701 | F2 702 | leftcursor 703 | 704 | modsmode 705 | 0 706 | relatedAppsMode 707 | 0 708 | 709 | type 710 | alfred.workflow.trigger.hotkey 711 | uid 712 | 6EEBB03A-5A12-4883-BEF4-2DAC11BF0FC0 713 | version 714 | 2 715 | 716 | 717 | config 718 | 719 | argument 720 | 2 721 | argumenttype 722 | 3 723 | triggerid 724 | io.mende.audioswitcher.out3 725 | triggername 726 | Select Output 3 727 | workflowonly 728 | 729 | 730 | type 731 | alfred.workflow.trigger.remote 732 | uid 733 | A0CE40D8-D874-48D7-903B-0C91A6B2F7DC 734 | version 735 | 1 736 | 737 | 738 | config 739 | 740 | lastpathcomponent 741 | 742 | onlyshowifquerypopulated 743 | 744 | removeextension 745 | 746 | text 747 | 748 | title 749 | Switched to {query} 750 | 751 | type 752 | alfred.workflow.output.notification 753 | uid 754 | 39B059B1-CD01-4C2D-8907-1E2F9262CD04 755 | version 756 | 1 757 | 758 | 759 | config 760 | 761 | action 762 | 0 763 | argument 764 | 3 765 | argumenttext 766 | 2 767 | focusedappvariable 768 | 769 | focusedappvariablename 770 | 771 | hotkey 772 | 99 773 | hotmod 774 | 9437184 775 | hotstring 776 | F3 777 | leftcursor 778 | 779 | modsmode 780 | 0 781 | relatedAppsMode 782 | 0 783 | 784 | type 785 | alfred.workflow.trigger.hotkey 786 | uid 787 | 9D6F6749-4476-48A0-BF59-8B80656B1F51 788 | version 789 | 2 790 | 791 | 792 | config 793 | 794 | argument 795 | 0 796 | argumenttype 797 | 3 798 | triggerid 799 | io.mende.audioswitcher.in1 800 | triggername 801 | Select Input 1 802 | workflowonly 803 | 804 | 805 | type 806 | alfred.workflow.trigger.remote 807 | uid 808 | 7155F88D-55F6-4608-BC2E-554BA0780537 809 | version 810 | 1 811 | 812 | 813 | config 814 | 815 | action 816 | 0 817 | argument 818 | 3 819 | argumenttext 820 | 0 821 | focusedappvariable 822 | 823 | focusedappvariablename 824 | 825 | hotkey 826 | 122 827 | hotmod 828 | 8912896 829 | hotstring 830 | F1 831 | leftcursor 832 | 833 | modsmode 834 | 0 835 | relatedAppsMode 836 | 0 837 | 838 | type 839 | alfred.workflow.trigger.hotkey 840 | uid 841 | 7A1840A7-3844-4206-9B9E-B0602C41361E 842 | version 843 | 2 844 | 845 | 846 | config 847 | 848 | argument 849 | 1 850 | argumenttype 851 | 3 852 | triggerid 853 | io.mende.audioswitcher.in2 854 | triggername 855 | Select Input 2 856 | workflowonly 857 | 858 | 859 | type 860 | alfred.workflow.trigger.remote 861 | uid 862 | C0967D8A-BEF8-44B5-BF2A-06BD127C8D73 863 | version 864 | 1 865 | 866 | 867 | config 868 | 869 | concurrently 870 | 871 | escaping 872 | 68 873 | script 874 | ./main.swift switch_by_name input $1 "$inputs" 875 | scriptargtype 876 | 1 877 | scriptfile 878 | 879 | type 880 | 11 881 | 882 | type 883 | alfred.workflow.action.script 884 | uid 885 | F6A49F45-6CB5-4CDF-BB3E-79B7715ACA0F 886 | version 887 | 2 888 | 889 | 890 | config 891 | 892 | action 893 | 0 894 | argument 895 | 3 896 | argumenttext 897 | 1 898 | focusedappvariable 899 | 900 | focusedappvariablename 901 | 902 | hotkey 903 | 120 904 | hotmod 905 | 8912896 906 | hotstring 907 | F2 908 | leftcursor 909 | 910 | modsmode 911 | 0 912 | relatedAppsMode 913 | 0 914 | 915 | type 916 | alfred.workflow.trigger.hotkey 917 | uid 918 | 82D538CB-521F-4F59-99A5-91AFC57E3CF3 919 | version 920 | 2 921 | 922 | 923 | config 924 | 925 | argument 926 | 2 927 | argumenttype 928 | 3 929 | triggerid 930 | io.mende.audioswitcher.in3 931 | triggername 932 | Select Input 3 933 | workflowonly 934 | 935 | 936 | type 937 | alfred.workflow.trigger.remote 938 | uid 939 | CBBA9D5E-DB01-490E-9C0F-F33A07F09E3A 940 | version 941 | 1 942 | 943 | 944 | config 945 | 946 | action 947 | 0 948 | argument 949 | 3 950 | argumenttext 951 | 2 952 | focusedappvariable 953 | 954 | focusedappvariablename 955 | 956 | hotkey 957 | 99 958 | hotmod 959 | 8912896 960 | hotstring 961 | F3 962 | leftcursor 963 | 964 | modsmode 965 | 0 966 | relatedAppsMode 967 | 0 968 | 969 | type 970 | alfred.workflow.trigger.hotkey 971 | uid 972 | A3266036-2FB4-4E74-B315-F9951154B58F 973 | version 974 | 2 975 | 976 | 977 | config 978 | 979 | argument 980 | 981 | argumenttype 982 | 0 983 | triggerid 984 | io.mende.audioswitcher.rotateout 985 | triggername 986 | Rotate Output 987 | workflowonly 988 | 989 | 990 | type 991 | alfred.workflow.trigger.remote 992 | uid 993 | 5F417B1B-FC67-40CE-8084-167913379DDE 994 | version 995 | 1 996 | 997 | 998 | config 999 | 1000 | concurrently 1001 | 1002 | escaping 1003 | 68 1004 | script 1005 | ./main.swift rotate_favorites output "$outputs" 1006 | scriptargtype 1007 | 1 1008 | scriptfile 1009 | 1010 | type 1011 | 11 1012 | 1013 | type 1014 | alfred.workflow.action.script 1015 | uid 1016 | BA2ED978-7611-4D11-9EA1-8A0A1E275FD0 1017 | version 1018 | 2 1019 | 1020 | 1021 | config 1022 | 1023 | action 1024 | 0 1025 | argument 1026 | 0 1027 | focusedappvariable 1028 | 1029 | focusedappvariablename 1030 | 1031 | hotkey 1032 | 111 1033 | hotmod 1034 | 9437184 1035 | hotstring 1036 | F12 1037 | leftcursor 1038 | 1039 | modsmode 1040 | 0 1041 | relatedAppsMode 1042 | 0 1043 | 1044 | type 1045 | alfred.workflow.trigger.hotkey 1046 | uid 1047 | 1AF283DE-8EDC-4006-AD54-91F4C226E5C9 1048 | version 1049 | 2 1050 | 1051 | 1052 | config 1053 | 1054 | argument 1055 | 1056 | argumenttype 1057 | 0 1058 | triggerid 1059 | io.mende.audioswitcher.rotatein 1060 | triggername 1061 | Rotate Input 1062 | workflowonly 1063 | 1064 | 1065 | type 1066 | alfred.workflow.trigger.remote 1067 | uid 1068 | 692C13A0-ADC1-4E71-8FA4-0157FF14C88F 1069 | version 1070 | 1 1071 | 1072 | 1073 | config 1074 | 1075 | concurrently 1076 | 1077 | escaping 1078 | 68 1079 | script 1080 | ./main.swift rotate_favorites input "$inputs" 1081 | scriptargtype 1082 | 1 1083 | scriptfile 1084 | 1085 | type 1086 | 11 1087 | 1088 | type 1089 | alfred.workflow.action.script 1090 | uid 1091 | 01427E94-9408-4123-A9BC-DF6185AB3A85 1092 | version 1093 | 2 1094 | 1095 | 1096 | config 1097 | 1098 | action 1099 | 0 1100 | argument 1101 | 0 1102 | focusedappvariable 1103 | 1104 | focusedappvariablename 1105 | 1106 | hotkey 1107 | 111 1108 | hotmod 1109 | 8912896 1110 | hotstring 1111 | F12 1112 | leftcursor 1113 | 1114 | modsmode 1115 | 0 1116 | relatedAppsMode 1117 | 0 1118 | 1119 | type 1120 | alfred.workflow.trigger.hotkey 1121 | uid 1122 | 86324099-F14A-4ADC-9C93-992F23163004 1123 | version 1124 | 2 1125 | 1126 | 1127 | config 1128 | 1129 | autopaste 1130 | 1131 | clipboardtext 1132 | {query} 1133 | ignoredynamicplaceholders 1134 | 1135 | transient 1136 | 1137 | 1138 | type 1139 | alfred.workflow.output.clipboard 1140 | uid 1141 | 00704246-FE25-4B27-86E9-2EB6EDF00D67 1142 | version 1143 | 3 1144 | 1145 | 1146 | config 1147 | 1148 | lastpathcomponent 1149 | 1150 | onlyshowifquerypopulated 1151 | 1152 | removeextension 1153 | 1154 | text 1155 | {query} 1156 | title 1157 | Devices copied to clipboard 1158 | 1159 | type 1160 | alfred.workflow.output.notification 1161 | uid 1162 | 09EBB07A-0EF4-4CDB-96E1-7A4EDC0561F4 1163 | version 1164 | 1 1165 | 1166 | 1167 | config 1168 | 1169 | concurrently 1170 | 1171 | escaping 1172 | 68 1173 | script 1174 | ./main.swift print_device_names $1 1175 | scriptargtype 1176 | 1 1177 | scriptfile 1178 | 1179 | type 1180 | 11 1181 | 1182 | type 1183 | alfred.workflow.action.script 1184 | uid 1185 | C46B89C0-5C32-4E45-84C4-714DAA27F2BD 1186 | version 1187 | 2 1188 | 1189 | 1190 | config 1191 | 1192 | argumenttrimmode 1193 | 0 1194 | argumenttype 1195 | 2 1196 | fixedorder 1197 | 1198 | items 1199 | [{"imagefile":"b171fc8163f973fcfe9f43d328811fe1096dcebe.png","title":"Outputs","arg":"output","subtitle":"Choose to Copy"},{"imagefile":"3ab9aedf8fbd94a12254709139ffcee0a288338b.png","title":"Inputs","arg":"input","subtitle":"Choose to Copy"}] 1200 | keyword 1201 | fetchaudiodevices 1202 | matchmode 1203 | 0 1204 | runningsubtext 1205 | 1206 | subtext 1207 | Choose which devices to copy to clipboard 1208 | title 1209 | Fetch Audio Devices 1210 | withspace 1211 | 1212 | 1213 | type 1214 | alfred.workflow.input.listfilter 1215 | uid 1216 | 9F22BA12-18B5-4FA5-B429-12DB07DBDC90 1217 | version 1218 | 1 1219 | 1220 | 1221 | readme 1222 | # Audio Switcher 1223 | This workflow supports quickly switching sound input and output devices. 1224 | 1225 | It offers hotkeys to quickly switch between three input favorites and output favorites. 1226 | You can also use a single hotkey to rotate among the favorites in sequence. 1227 | Those can also be triggered using Alfred Remote. 1228 | 1229 | ## Listing Devices 1230 | Once installed, use the `fetchaudiodevices` command in Alfred. Once you have selected either "Outputs" or "Inputs", 1231 | the workflow will copy a list of devices to the Clipboard. This is a convenience feature to support filling the 1232 | *Ignorelist*, *Output Favorites* and *Input Favorites*. (See below) 1233 | 1234 | ## Parameter Examples 1235 | 1236 | ### Ignorelist 1237 | The value 1238 | ``` 1239 | External Headphones 1240 | iPhone Microphone 1241 | ``` 1242 | causes both listed devices not to be listed when selecting inputs or outputs. 1243 | 1244 | 1245 | ### Output Favorites 1246 | The value 1247 | ``` 1248 | MacBook Pro Speakers 1249 | RØDE Connect Virtual 1250 | External Screen 1251 | ``` 1252 | means the following: 1253 | - *⌘ + F1* will select MacBook Pro Speakers. 1254 | - *⌘ + F2* will select RØDE Connect Virtual. 1255 | - *⌘ + F3* will select External Screen. 1256 | - *⌘ + F12* will rotate among these three outputs. 1257 | 1258 | ### Input Favorites 1259 | The value 1260 | ``` 1261 | MacBook Pro Microphone 1262 | RØDE Connect Stream 1263 | ``` 1264 | means the following: 1265 | - *⌥ + F1* will select MacBook Pro Microphone. 1266 | - *⌥ + F2* will select RØDE Connect Stream. 1267 | - *⌥ + F3* will have no effect. 1268 | - *⌥ + F12* will rotate among these two outputs. 1269 | 1270 | ## Friendly Names 1271 | You might want to specify friendly names for your inputs and outputs. For this you can use the favorite lists and add a freindly name separated by a semicolon (`;`). Example: 1272 | ``` 1273 | MacBook Pro Speakers;Mac 1274 | RØDE Connect Virtual;RØDE 1275 | External Screen 1276 | ``` 1277 | 1278 | For entries without a friendly name, the official name will be used. 1279 | Friendly names are used in the `in` and `out` lists in this workflow. 1280 | uidata 1281 | 1282 | 00704246-FE25-4B27-86E9-2EB6EDF00D67 1283 | 1284 | xpos 1285 | 685 1286 | ypos 1287 | 1415 1288 | 1289 | 01427E94-9408-4123-A9BC-DF6185AB3A85 1290 | 1291 | note 1292 | rotateInput 1293 | xpos 1294 | 630 1295 | ypos 1296 | 1230 1297 | 1298 | 09EBB07A-0EF4-4CDB-96E1-7A4EDC0561F4 1299 | 1300 | xpos 1301 | 950 1302 | ypos 1303 | 1415 1304 | 1305 | 1450496C-74BC-4EDE-930B-ADC6027C5449 1306 | 1307 | xpos 1308 | 405 1309 | ypos 1310 | 180 1311 | 1312 | 1AF283DE-8EDC-4006-AD54-91F4C226E5C9 1313 | 1314 | xpos 1315 | 200 1316 | ypos 1317 | 1065 1318 | 1319 | 39B059B1-CD01-4C2D-8907-1E2F9262CD04 1320 | 1321 | xpos 1322 | 985 1323 | ypos 1324 | 545 1325 | 1326 | 3AE8EB58-5F7D-49B6-98C1-4BAE5E79FC2E 1327 | 1328 | note 1329 | setOutput 1330 | xpos 1331 | 630 1332 | ypos 1333 | 40 1334 | 1335 | 3B2897E7-E242-4504-A297-602265B0011F 1336 | 1337 | note 1338 | setOutput 1339 | xpos 1340 | 630 1341 | ypos 1342 | 435 1343 | 1344 | 5F417B1B-FC67-40CE-8084-167913379DDE 1345 | 1346 | xpos 1347 | 390 1348 | ypos 1349 | 1040 1350 | 1351 | 692C13A0-ADC1-4E71-8FA4-0157FF14C88F 1352 | 1353 | xpos 1354 | 395 1355 | ypos 1356 | 1205 1357 | 1358 | 6CDEB1A2-F0E3-4C17-955A-7AA171D8C899 1359 | 1360 | xpos 1361 | 210 1362 | ypos 1363 | 330 1364 | 1365 | 6EEBB03A-5A12-4883-BEF4-2DAC11BF0FC0 1366 | 1367 | xpos 1368 | 205 1369 | ypos 1370 | 440 1371 | 1372 | 7155F88D-55F6-4608-BC2E-554BA0780537 1373 | 1374 | xpos 1375 | 390 1376 | ypos 1377 | 675 1378 | 1379 | 71AAE21C-028C-45CE-AB44-1378572652A9 1380 | 1381 | xpos 1382 | 210 1383 | ypos 1384 | 180 1385 | 1386 | 7A1840A7-3844-4206-9B9E-B0602C41361E 1387 | 1388 | xpos 1389 | 200 1390 | ypos 1391 | 690 1392 | 1393 | 82D538CB-521F-4F59-99A5-91AFC57E3CF3 1394 | 1395 | xpos 1396 | 200 1397 | ypos 1398 | 800 1399 | 1400 | 86324099-F14A-4ADC-9C93-992F23163004 1401 | 1402 | xpos 1403 | 200 1404 | ypos 1405 | 1230 1406 | 1407 | 864A20DF-C5E2-444E-B084-9CD126BED7DF 1408 | 1409 | xpos 1410 | 405 1411 | ypos 1412 | 430 1413 | 1414 | 9D6F6749-4476-48A0-BF59-8B80656B1F51 1415 | 1416 | xpos 1417 | 200 1418 | ypos 1419 | 550 1420 | 1421 | 9F22BA12-18B5-4FA5-B429-12DB07DBDC90 1422 | 1423 | xpos 1424 | 190 1425 | ypos 1426 | 1415 1427 | 1428 | A0CE40D8-D874-48D7-903B-0C91A6B2F7DC 1429 | 1430 | xpos 1431 | 405 1432 | ypos 1433 | 535 1434 | 1435 | A3266036-2FB4-4E74-B315-F9951154B58F 1436 | 1437 | xpos 1438 | 200 1439 | ypos 1440 | 910 1441 | 1442 | AD6FA975-C31E-4D56-BF48-EBBC634EB89E 1443 | 1444 | xpos 1445 | 405 1446 | ypos 1447 | 325 1448 | 1449 | AFF1A33C-2AE0-4CA1-8B00-04BB87A5F7FE 1450 | 1451 | xpos 1452 | 210 1453 | ypos 1454 | 40 1455 | 1456 | B066EEAB-4F3C-4516-9F00-E8FD7A5439B6 1457 | 1458 | xpos 1459 | 405 1460 | ypos 1461 | 40 1462 | 1463 | BA2ED978-7611-4D11-9EA1-8A0A1E275FD0 1464 | 1465 | note 1466 | rotateOutput 1467 | xpos 1468 | 630 1469 | ypos 1470 | 1065 1471 | 1472 | C0967D8A-BEF8-44B5-BF2A-06BD127C8D73 1473 | 1474 | xpos 1475 | 395 1476 | ypos 1477 | 795 1478 | 1479 | C46B89C0-5C32-4E45-84C4-714DAA27F2BD 1480 | 1481 | note 1482 | fetchaudiodevices 1483 | xpos 1484 | 435 1485 | ypos 1486 | 1415 1487 | 1488 | CBBA9D5E-DB01-490E-9C0F-F33A07F09E3A 1489 | 1490 | xpos 1491 | 395 1492 | ypos 1493 | 900 1494 | 1495 | F6A49F45-6CB5-4CDF-BB3E-79B7715ACA0F 1496 | 1497 | note 1498 | setInput 1499 | xpos 1500 | 630 1501 | ypos 1502 | 795 1503 | 1504 | FCE19CD4-E3AE-4361-8B59-F357914A629C 1505 | 1506 | note 1507 | setInput 1508 | xpos 1509 | 630 1510 | ypos 1511 | 180 1512 | 1513 | 1514 | userconfigurationconfig 1515 | 1516 | 1517 | config 1518 | 1519 | default 1520 | out 1521 | placeholder 1522 | 1523 | required 1524 | 1525 | trim 1526 | 1527 | 1528 | description 1529 | Alfred Keyword to show available outputs. 1530 | label 1531 | Keyword for Output Selection 1532 | type 1533 | textfield 1534 | variable 1535 | output_keyword 1536 | 1537 | 1538 | config 1539 | 1540 | default 1541 | in 1542 | placeholder 1543 | 1544 | required 1545 | 1546 | trim 1547 | 1548 | 1549 | description 1550 | Alfred Keyword to show available inputs. 1551 | label 1552 | Keyword for Input Selection 1553 | type 1554 | textfield 1555 | variable 1556 | input_keyword 1557 | 1558 | 1559 | config 1560 | 1561 | default 1562 | 1563 | required 1564 | 1565 | trim 1566 | 1567 | verticalsize 1568 | 9 1569 | 1570 | description 1571 | Devices to Ignore (one per line), both input and output. 1572 | label 1573 | Ignorelist 1574 | type 1575 | textarea 1576 | variable 1577 | ignorelist 1578 | 1579 | 1580 | config 1581 | 1582 | default 1583 | 1584 | required 1585 | 1586 | trim 1587 | 1588 | verticalsize 1589 | 6 1590 | 1591 | description 1592 | List of up to three output names (one per line) – Hint: Get them from the "fetchaudiodevices" command 1593 | label 1594 | Output Favorites 1595 | type 1596 | textarea 1597 | variable 1598 | outputs 1599 | 1600 | 1601 | config 1602 | 1603 | default 1604 | 1605 | required 1606 | 1607 | trim 1608 | 1609 | verticalsize 1610 | 6 1611 | 1612 | description 1613 | List of up to three input names (one per line) – Hint: Get them from the "fetchaudiodevices" command 1614 | label 1615 | Input Favorites 1616 | type 1617 | textarea 1618 | variable 1619 | inputs 1620 | 1621 | 1622 | version 1623 | 1.3.0 1624 | webaddress 1625 | https://github.com/TobiasMende/alfred-audio-switcher 1626 | 1627 | 1628 | -------------------------------------------------------------------------------- /workflow/main.swift: -------------------------------------------------------------------------------- 1 | #!/usr/bin/swift 2 | import Foundation 3 | import CoreAudio 4 | 5 | let arguments = CommandLine.arguments 6 | guard arguments.count > 2 else { 7 | printUsageAndExit() 8 | exit(1) 9 | } 10 | 11 | let command = arguments[1] 12 | let type = arguments[2] == "input" ? DeviceType.input : DeviceType.output 13 | 14 | if command == "list" { 15 | printDeviceItems(type: type) 16 | } else if command == "switch_by_id" && arguments.count > 3 { 17 | switchDeviceById(type: type, deviceIDAsString: arguments[3]) 18 | } else if command == "print_device_names" { 19 | printDeviceNames(type: type) 20 | } else if command == "switch_by_name" && arguments.count > 3 { 21 | switchDeviceByDeviceIndexAndList(type: type, deviceIndexAsString: arguments[3]) 22 | } else if command == "rotate_favorites" && arguments.count > 2 { 23 | rotateFavorites(type: type) 24 | }else { 25 | printUsageAndExit() 26 | } 27 | 28 | 29 | enum DeviceType { 30 | case input, output 31 | } 32 | 33 | func createPropertyAddress(selector: AudioObjectPropertySelector) -> AudioObjectPropertyAddress { 34 | return AudioObjectPropertyAddress( 35 | mSelector: selector, 36 | mScope: kAudioObjectPropertyScopeGlobal, 37 | mElement: kAudioObjectPropertyElementMain 38 | ) 39 | } 40 | 41 | func getPropertyAddress(type: DeviceType) -> AudioObjectPropertyAddress { 42 | let propertySelector: AudioObjectPropertySelector = (type == .input) ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice 43 | return createPropertyAddress(selector: propertySelector) 44 | } 45 | 46 | func getAudioDeviceNameById(deviceID: AudioDeviceID) -> String { 47 | guard let deviceName = getDeviceName(deviceID: deviceID) else { 48 | fatalError("Error: Unable to get name for device ID \(deviceID)") 49 | } 50 | 51 | return deviceName 52 | } 53 | 54 | func getAudioDeviceIdByName(deviceName: String, type: DeviceType) -> AudioDeviceID? { 55 | let devices = getAudioDeviceList(type: type) 56 | 57 | let foundDevice = devices.first { device in 58 | device.name == deviceName 59 | } 60 | 61 | return foundDevice?.id 62 | } 63 | 64 | func setDefaultAudioDevice(type: DeviceType, deviceID: AudioDeviceID) -> String? { 65 | var propertyAddress = getPropertyAddress(type: type) 66 | 67 | var newDeviceID = deviceID 68 | let propertySize = UInt32(MemoryLayout.size) 69 | 70 | let status = AudioObjectSetPropertyData(AudioObjectID(kAudioObjectSystemObject), &propertyAddress, 0, nil, propertySize, &newDeviceID) 71 | if status != noErr { 72 | fatalError("Error: Unable to set default \(type) device") 73 | } 74 | 75 | if(type == .output) { 76 | let syncSoundEffectsOutput = getEnvironmentVariable(named: "sync_sound_effects_output") == "1" ? true : false 77 | if(syncSoundEffectsOutput) { 78 | setSoundEffectsOutput(to: deviceID) 79 | } 80 | } 81 | 82 | return getAudioDeviceNameById(deviceID: deviceID) 83 | } 84 | 85 | func setSoundEffectsOutput(to deviceID: AudioDeviceID) { 86 | var propertyAddress = createPropertyAddress(selector: kAudioHardwarePropertyDefaultSystemOutputDevice) 87 | var newDeviceID = deviceID 88 | let propertySize = UInt32(MemoryLayout.size) 89 | 90 | let status = AudioObjectSetPropertyData(AudioObjectID(kAudioObjectSystemObject), &propertyAddress, 0, nil, propertySize, &newDeviceID) 91 | if status != noErr { 92 | fatalError("Error: Unable to set default \(type) device") 93 | } 94 | } 95 | 96 | func getDeviceName(deviceID: AudioDeviceID) -> String? { 97 | var nameSize = UInt32(MemoryLayout.size) 98 | var deviceName: CFString = "" as CFString 99 | var address = createPropertyAddress(selector: kAudioDevicePropertyDeviceNameCFString) 100 | 101 | let status = withUnsafeMutablePointer(to: &deviceName) { ptr in 102 | AudioObjectGetPropertyData(deviceID, &address, 0, nil, &nameSize, ptr) 103 | } 104 | 105 | if status == noErr, let name = deviceName as String? { 106 | return name 107 | } else { 108 | return nil 109 | } 110 | } 111 | 112 | func getDefaultAudioDevice(type: DeviceType) -> (name: String, id: AudioDeviceID) { 113 | var deviceID = AudioDeviceID() 114 | var propertySize = UInt32(MemoryLayout.size) 115 | var propertyAddress = getPropertyAddress(type: type) 116 | 117 | let status = AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &propertyAddress, 0, nil, &propertySize, &deviceID) 118 | if status != noErr { 119 | fatalError("Error: Unable to get default \(type) device") 120 | } 121 | guard let deviceName = getDeviceName(deviceID: deviceID) else { 122 | fatalError("Failed to retrieve device Name for \(deviceID)") 123 | } 124 | return (name: deviceName, id: deviceID) 125 | } 126 | 127 | func getAudioDeviceList(type: DeviceType) -> [(name: String, id: AudioDeviceID)] { 128 | var propertySize: UInt32 = 0 129 | var address = createPropertyAddress(selector: kAudioHardwarePropertyDevices) 130 | 131 | var status = AudioObjectGetPropertyDataSize(AudioObjectID(kAudioObjectSystemObject), &address, 0, nil, &propertySize) 132 | guard status == noErr else { 133 | fatalError("Error: Unable to get the size of the audio devices array") 134 | } 135 | 136 | let deviceCount = Int(propertySize) / MemoryLayout.size 137 | var deviceIDs = [AudioDeviceID](repeating: 0, count: deviceCount) 138 | 139 | status = AudioObjectGetPropertyData(AudioObjectID(kAudioObjectSystemObject), &address, 0, nil, &propertySize, &deviceIDs) 140 | guard status == noErr else { 141 | fatalError("Error: Unable to get audio devices") 142 | } 143 | 144 | var deviceList: [(name: String, id: AudioDeviceID)] = [] 145 | for id in deviceIDs { 146 | let scope: AudioObjectPropertyScope = (type == .input) ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput 147 | var streamAddress = AudioObjectPropertyAddress( 148 | mSelector: kAudioDevicePropertyStreams, 149 | mScope: scope, 150 | mElement: kAudioObjectPropertyElementMain) 151 | var streamSize: UInt32 = 0 152 | 153 | status = AudioObjectGetPropertyDataSize(id, &streamAddress, 0, nil, &streamSize) 154 | if status != noErr || streamSize == 0 { 155 | continue // Skip device if it doesn't have streams for the specified type 156 | } 157 | 158 | guard let deviceName = getDeviceName(deviceID: id) else { 159 | continue 160 | } 161 | 162 | deviceList.append((name: deviceName, id: id)) 163 | 164 | } 165 | 166 | return deviceList 167 | } 168 | 169 | func convertStringToDeviceID(deviceIDString: String) -> AudioDeviceID? { 170 | if let deviceIDInt = UInt32(deviceIDString) { 171 | return AudioDeviceID(deviceIDInt) 172 | } else { 173 | fatalError("Invalid Device ID String") 174 | } 175 | } 176 | 177 | 178 | func deviceToJson(device: (name: String, id: AudioDeviceID), friendlyName: String, isDefault: Bool, type: DeviceType) -> String { 179 | let iconName = isDefault ? "\(type)_selected.png" : "\(type).png" 180 | return "{\"title\": \"\(friendlyName)\", \"uid\": \"\(device.name)\", \"autocomplete\": \"\(friendlyName)\", \"arg\": \"\(device.id)\", \"icon\": {\"path\": \"./icons/\(iconName)\"}}" 181 | } 182 | 183 | func filterAudioDevices(devices: [(name: String, id: AudioDeviceID)], ignoreList: [String]) -> [(name: String, id: AudioDeviceID)] { 184 | return devices.filter { !ignoreList.contains($0.name) } 185 | } 186 | 187 | func printDeviceNames(type: DeviceType) { 188 | getAudioDeviceList(type: type).forEach { device in 189 | print(device.name) 190 | } 191 | } 192 | 193 | func convertFavoritesList(favoritesAsMultilineString: String) -> [String: String] { 194 | let favoriteList = convertMultilineArgumentToList(argument: favoritesAsMultilineString) 195 | 196 | var resultMap: [String: String] = [:] 197 | 198 | for favoriteLine in favoriteList { 199 | let components = favoriteLine.split(separator: ";", maxSplits: 1, omittingEmptySubsequences: true) 200 | 201 | if components.count == 2 { 202 | // If there are two components, we have both key and value 203 | let key = String(components[0]).trimmingCharacters(in: .whitespaces) 204 | let value = String(components[1]).trimmingCharacters(in: .whitespaces) 205 | resultMap[key] = value 206 | } else if components.count == 1 { 207 | // If there's no semicolon, we can still add the key with an empty value 208 | let key = String(components[0]).trimmingCharacters(in: .whitespaces) 209 | resultMap[key] = key 210 | } 211 | } 212 | 213 | return resultMap 214 | } 215 | 216 | func printDeviceItems(type: DeviceType) { 217 | let favoritesAsMultilineString = getAppropriateDeviceList(type: type) 218 | let ignoreList = convertMultilineArgumentToList(argument: getEnvironmentVariable(named: "ignorelist")) 219 | let favoriteList = convertFavoritesList(favoritesAsMultilineString: favoritesAsMultilineString) 220 | let defaultDevice = getDefaultAudioDevice(type: type) 221 | let devices = getAudioDeviceList(type: type) 222 | let devicesAsJson = filterAudioDevices(devices: devices, ignoreList: ignoreList).map { device in 223 | let isDefault = (defaultDevice.id == device.id) 224 | let friendlyName = favoriteList[device.name] ?? device.name 225 | return deviceToJson(device: device, friendlyName: friendlyName, isDefault: isDefault, type: type) 226 | }.joined(separator: ",") 227 | 228 | print("{\"items\": [\(devicesAsJson)]}") 229 | } 230 | 231 | func getAppropriateDeviceList(type: DeviceType) -> String { 232 | return getEnvironmentVariable(named: (type == .output ? "outputs" : "inputs")) 233 | } 234 | 235 | func switchDeviceById(type: DeviceType, deviceIDAsString: String) { 236 | guard let deviceID = convertStringToDeviceID(deviceIDString: deviceIDAsString) else { 237 | fatalError("Could not convert to AudioDeviceId: \(deviceIDAsString)") 238 | } 239 | guard let selectedDevice = setDefaultAudioDevice(type: type, deviceID: deviceID) else { 240 | fatalError("Device Not Found: \(deviceID)") 241 | } 242 | 243 | print(selectedDevice) 244 | } 245 | 246 | func getEnvironmentVariable(named name: String) -> String { 247 | return ProcessInfo.processInfo.environment[name] ?? "" 248 | } 249 | 250 | func switchDeviceByDeviceIndexAndList(type: DeviceType, deviceIndexAsString: String) { 251 | guard let deviceIndex = Int(deviceIndexAsString) else { 252 | fatalError("Invalid Device Index: \(deviceIndexAsString)") 253 | } 254 | 255 | let deviceList = convertMultilineArgumentToList(argument: getAppropriateDeviceList(type: type)) 256 | 257 | guard deviceIndex < deviceList.count else { 258 | fatalError("Invalid Index Passed") 259 | } 260 | 261 | guard let deviceFromList = deviceList[deviceIndex].split(separator: ";").first else { 262 | fatalError("Invalid Device Index: \(deviceIndex)") 263 | } 264 | 265 | guard let deviceID = getAudioDeviceIdByName(deviceName: String(deviceFromList), type: type) else { 266 | fatalError("Device not found: Index: \(deviceIndex), deviceList: \(deviceList)") 267 | } 268 | 269 | guard let selectedDevice = setDefaultAudioDevice(type: type, deviceID: deviceID) else { 270 | fatalError("Device Not Found: \(deviceID)") 271 | } 272 | 273 | print(selectedDevice) 274 | } 275 | 276 | func convertMultilineArgumentToList(argument: String) -> [String] { 277 | return argument.split(separator: "\n").map(String.init) 278 | } 279 | 280 | func rotateFavorites(type: DeviceType) { 281 | let defaultDevice = getDefaultAudioDevice(type: type) 282 | let deviceList = convertMultilineArgumentToList(argument: getAppropriateDeviceList(type: type)).map { String($0.split(separator: ";").first!) } 283 | guard deviceList.count > 0 else { 284 | fatalError("No devices in list") 285 | } 286 | 287 | let defaultDeviceIndex = deviceList.firstIndex(of: defaultDevice.name) ?? -1 288 | let nextDeviceIndex = (defaultDeviceIndex + 1) % deviceList.count 289 | guard let nextDeviceName = deviceList[nextDeviceIndex].split(separator: ";").first else { 290 | fatalError("Device not found at index: \(nextDeviceIndex)") 291 | } 292 | guard let nextDeviceID = getAudioDeviceIdByName(deviceName: String(nextDeviceName), type: type) else { 293 | fatalError("Device not found: \(nextDeviceName)") 294 | } 295 | 296 | guard let selectedDevice = setDefaultAudioDevice(type: type, deviceID: nextDeviceID) else { 297 | fatalError("Device Not Found: \(nextDeviceID)") 298 | } 299 | 300 | print(selectedDevice) 301 | } 302 | 303 | 304 | func printUsageAndExit() { 305 | print("Usage: ./main.swift [| ]") 306 | print("command: (list | switch_by_id | switch_by_name | rotate_favorites | print_device_names)") 307 | print("type: (input | output)") 308 | exit(1) 309 | } 310 | --------------------------------------------------------------------------------