SeekBar — Volume — Google Cast
If you are developing media playback application with Google Cast (Chromecast) support you maybe want to implement volume change slider to adjust volume on receiver device (TV, for example) during casting as well as media volume on android phone.
I ran into this issue and in this article I’ll show the solution using Kotlin, Strategy pattern and Lifecycle-aware components. As you may have already guessed SeekBar
will be used as a slider.
First of all let’s briefly outline the approach. There is one main user class which purpose is to glue SeekBar
with volume controlling. It responsible for handling cast session events and switching between appropriate implementations.
So, we need two volume control implementations: one for AudioManager.STREAM_MUSIC
and another one for cast session. According to the Strategy pattern, write abstract class with common interface. Call it Volumizer
:
start()
and stop()
methods used to subscribe and unsubscribe listeners to external volume changes. The rest is obvious.
Then write implementation to adjust music stream on a device. Essentially, it’s a well-known way that used AudioManager
to get/set volume and ContentObserver
for monitoring volume changing.
Next implement managing the volume of cast receiver. For this we need an instance of CastSession
to get/set volume and Cast.Listener
for monitoring volume changing. Note that the volume in CastSession
is in the range [0.0, 1.0]
, so we have to adapt it to the base class interface where volume values are integers (like Seekbar has too). For this reason we use VOLUME_STEP
and VOLUME_MAX
constants — 20 steps with 0.05 weight.
Now let’s write central class of the solution — SeekBarCastAwareVolumizer
:
The main points of this class are:
- Check
SessionManager.currentCastSession
to instantiate properVolumizer
implementation in the constructor. - Using
SessionManagerListener
to handle starting and ending casting session to change behavior by using differentVolumizers
. - In
onStop
method of activity we must remove all listeners. Otherwise there will be an activity leak.LifecycleObserver
allows this class to achieve that and be self-sufficient. seekBar.isSaveEnabled = false
— to disable saving state of the view, because we synсhronizing Seekbar with current volume inonStart
.
Wrapping up
Finally, usage of the class looks that way:
Just write one line of code and get the magic — now your SeekBar can change the volume simply playing media on the phone and while streaming to a TV or sound system as well.
Full code you may find here.