Update on current progress...
I'm almost ready for a v0.4.0 release.
This has a TON of changes:
It uses websocket connections wherever possible, this is a bit faster than HTTP requests, and allows for subscribing to a few more things than I could previously subscribe to, such as loadAudioClip and favorites.
Being able to subscribe to loadAudioClip (the API that allows for the non-interrupting TTS/MP3 playing) means I know exactly when the previous message has finished. And since I know that, I added a QUEUE to these. You can send non-interrupting TTS or other MP3 URIs to your Sonos left, right, and center and it'll just queue them all up and play them in order. No overlapping. No long gaps between messages. No gaps between messages at all, actually! No need to futz around with crap like "wait until stopped -> send next". None of that. Just send away and Sonos Advanced will take care of the rest.
I've also added a "high priority" version of the non-interrupting commands, so if you have some long TTS playing or something, and say you have an MP3 that plays when your doorbell rings, you can set that off with the high priority one and it'll play immediately rather than being queued up. And it'll play right over top of what's playing, in a non-interrupting way, AND if there's a low priority TTS or other URI being played, it plays non-interrupting right over top of it, too. So let's say you have some minute long "morning annoucement TTS" that's playing and someone rings the doorbell... the morning announcement will have "ducked" (lowered) the volume of your music so it can play non-interrupting, then the doorbell with duck both the music and the other TTS so it can play, then when it's done, it goes back to the previous TSS and when that's done back to your music.
Device Discovery now finds "secondary" speakers and adds their IP to the primary's "Data" section. On the primary (left channel, usually) there's a new preference for "Create child device right channel? (stereo pair only)". If this is enabled, it creates a child device for the right speaker, which doesn't do much, but one thing it does do is maintain its own websocket connection to the right channel speaker, and then any of the non-interrupting messages play on BOTH speakers. It's not properly time-sync'd, but it's within a few milliseconds and for the most part I can't even tell that it's just playing on both independently.
There's no (current) way to properly play anything with loadAudioClip on both speakers, it's just how Sonos made it. I can play it independently on both, with it close enough to synced. If you find the right channel 'echo-y' and out of sync, just turn the toggle back off and it'll just play on the left speaker.
Sonos has a built-in chime it can play with loadAudioClip, and since I can queue things up back-to-back with zero gap between them, that means I can queue up that chime to play before any TTS messages. So if you want a chime before your speakers just start shouting at you, there's an option for that now, too. Or leave it off and it'll just play the TTS with no chime.
I've reorganized and optimized quite a bit of the code, and many more parts are @CompileStatic annotated. In my testing so far I'm finding the 0.4.0 branch to be LESS CPU usage than the built-in Sonos app. Right now I'm seeing just under 2% total CPU usage by both the app and all of the driver code, and that's with pretty heavy development being done AND logging a TON of crap at trace level. If I turn trace logging off, it's closer to 1% total usage. When I ran the built-in Sonos app, it always totaled around 2-2.5% for me, so Sonos Advanced being less than that is pretty amazing.
As part of the Favorites matching, I've added an optional "Favorites" child device. You can toggle it on any/all of your player devices. I recommend only using one, since it'll just be duplicated data anyway. All the Favorites child does is keep a copy of the latest favorites in its state, so you don't have to click on "getFavorites" each time you want to see what number a favorite is.
With this addition, I'm also able to now subscribe to the favorites namespace using web sockets. So if you add/remove/change favorites, Sonos Advanced immediately updates the cached list of favorites it uses for matching, and the favorites state on your favorites child device.
The "is a favorite playing" code has been rewritten significantly too. It now runs FAR less often. So it's now triggered when a new track starts playing, and 95% of the time there's just a single call to "is a favorite playing". But like 5% of the time Sonos sends duplicate "new track started playing" messages with only "current position" changed, so it's not quite as low as possible, but it's close. And it's been optimized a lot too, to the point where it should have almost no impact on CPU usage overall, so feel free to turn it back on if you had it off, you'll probably not even notice a difference in resource usage.
Next step is pulling in some more websocket goodness to the group/ungroup/join/unjoin stuff, and adding a few more features to the Group Devices.
And I'll be adding support for "Sonos Playlists" in the same manner that Favorites are supported now. Well, at least for loading them. Haven't looked into whether there's any way to know whether there's a Sonos Playlist 'currently playing' like I can for favorites.
So lots of good stuff coming, probably this weekend, maybe sooner.