Apologies for resurrecting a relatively old thread, but there is surprisingly little information about this issue. I managed to figure out the solution, and wanted to add it here for anyone else who ends up here as I did.
Problem 1: The Universal Media Player documentation is wrong, it says the volume_mute service should toggle the current state. However it should actually set to muted/unmuted based on the is_volume_muted parameter passed with the service call.
Problem 2: I can’t find anywhere in the documentation that explains how to pass through the ‘is_volume_muted’ parameter from the original service call to the new one we are making to the backend. After digging through the source, I eventually found that the answer was simple: all the service data parameters just become variables in the template.
Solution: After figuring out the two issues above, the config was actually quite straightforward (I’ve omitted some of the services for brevity, but provided enough context to hopefully give you an idea of what’s needed where):
This example config ensures that most actions pass through to either Chromecast or Kodi, depending on whichever is currently active. But volume controls will always manage the volume of the TV itself. Don’t forget to define volume_up and volume_down, which I didn’t include here because they are shown in the Universal Media Player documentation already and work fine.