
- Stream audio to icecast, from either line-in or from the desktop audio output;
- Acquire that same audio in OBS, to stream to RTMP;
- Switch the audio input that we're reading from under cron control.
Every single layer of software involved in this process conspires to make this as difficult as possible, especially the automation.
Things that don't work:
- Nicecast, which is no longer supported on macOS 10.15.
- ffmpeg, which can't read audio from AVFoundation devices without glitching. There are five year old patches that might have fixed this that never landed and no longer apply.
- DarkIce, which claims to support CoreAudio but does not (also the author is a dick).
- JackAudio, which does not work on macOS 10.15.
- Streaming to icecast from OBS, because you can't stream to two destinations at the same time without giving up the ability to also archive video to disk.
Here's how I made it go:
- For audio input to the video stream: OBS doesn't support even the most remedial scripting, through AppleScript or otherwise, but it does let you assign a hot-key to a "scene". So make a different scene for each audio input, assign a function key to it, and use osascript to type those function keys at OBS at the appropriate time. Pepper your scripts with "sleep" statements until things mostly work, mostly.
- To record from the system audio in OBS, I had been using iShowU, because OBS didn't seem to support anything else that works on 10.15. And by "iShowU" I mean "iShowUAudioCapture", not "iShowU Instant" or "iShowU Studio", which are separate paid products. But, see below...
- For audio input to the icecast stream: Audio Hijack supports the devices well, but also has not even the most remedial automation support. And doesn't have the "scene hotkey" thing that OBS does, though it does let you type Cmd-R to play/pause. But, I found a kludge:
- Launch Audio Hijack. Set it up for Line In → Icecast.
- Export as "line-in.ahsession"
- Reconfigure it for System Audio
- Export as "system-audio.ahsession"
- Then to switch inputs:killall 'Audio Hijack' 2>&-
while ( killall -0 'Audio Hijack' 2>&- ); do sleep 1; done
rm ~/Library/Application\ Support/Audio\ Hijack/Sessions.plist
open line-in.ahsession
osascript -e 'tell application "Audio Hijack" to activate' \
-e 'tell application "System Events" to keystroke "r" using {command down}'This will drop and re-open the connection every time you switch, which is less than ideal, but here we are.
- Oh, but wait, if Audio Hijack is reading from System Audio, then iShowU gets silence. So you get audio on the Icecast stream and nothing in OBS. Awesome. Having two programs able to read from the same audio source at the same time would be too much to ask. What do you think this is, Linux?
- The fix to that is to install yet another program, Loopback.
- Update both of the saved Audio Hijack configurations to split to two outputs, the Icecast server, as well as to a Loopback input.
- Update all of the OBS scenes to take audio from Loopback instead of from iShowU.
- Kick iShowU unceremoniously to the curb.
This means that to fix the bug that Audio Hijack won't play nice and allow iShowU to read at the same time, I had to spend another $100 on Loopback. I would have been a lot more irritated by this if not for the fact that I bought Nicecast from Rogue Amoeba in 2006 and they only made me pay for it once. So, kudos to them for having kept alive the business model where software is a product that you buy rather than a service that you rent. So, yeah, take my money.
- Oh yeah, and then good luck making the task of "crontab calls osascript which types a keystroke at an app" work. It's a whole other ordeal that involves adding every program under the sun to the list under "System Preferences → Security → Accessiblity", and clicking "Ok" on an endless series of dialogs that will pop up at the most inconvenient possible time.