7

I want to implement volume change as seen in Youtube app while casting, like if app is in background or on lock screen

Like this

private void createSession() {
    ComponentName receiver = new ComponentName(getPackageName(), RemoteReceiver.class.getName());
    mediaSession = new MediaSessionCompat(this, "PlayerService", receiver, null);
    mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
            MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
    mediaSession.setPlaybackState(new PlaybackStateCompat.Builder()
            .setState(PlaybackStateCompat.STATE_PLAYING, 0, 1f)
            .setActions(PlaybackStateCompat.ACTION_PLAY_PAUSE)
            .build());
    AudioManager audioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
    audioManager.requestAudioFocus(new AudioManager.OnAudioFocusChangeListener() {
        @Override
        public void onAudioFocusChange(int focusChange) {
            // Ignore
        }
    }, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
    mediaSession.setActive(true);

    mediaRouter = MediaRouter.getInstance(this);
    mediaRouter.setMediaSessionCompat(mediaSession);
}

Now I get the slider just like Image above and it responds to volume buttons, but I dont receive change in my broadcast receiver.

ingsaurabh
  • 15,249
  • 7
  • 52
  • 81

1 Answers1

4

All you have to do is create a MediaSessionCompat with a VolumeProviderCompat.

// Here is a volume provider which sets the volume of a remote route.
// Extend VolumeProviderCompat with your own implementation.
public static class RemoteVolume extends VolumeProviderCompat {
    public RemoteVolume(MediaRouter.RouteInfo routeInfo) {
        super(VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE, STEPS, 0);
        this.stepSize = routeInfo.getVolumeMax() / STEPS;
        this.routeInfo = routeInfo;
    }

    @Override
    public void onSetVolumeTo(int volume) {
        routeInfo.requestSetVolume(volume * stepSize);
        setCurrentVolume(volume);
    }

    @Override
    public void onAdjustVolume(int delta) {
        int newVolume = getCurrentVolume() + delta;
        routeInfo.requestSetVolume(newVolume * stepSize);
        setCurrentVolume(newVolume);
    }
}

Then, connect the VolumeProviderCompat to your MediaSessionCompat:

MediaSessionCompat session = new MediaSessionCompat(context, TAG);

// might need some of these flags
session.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
            MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS |
            MediaSessionCompat.FLAG_HANDLES_QUEUE_COMMANDS);

// the volume buttons are routed to this session when it is
// active and currently playing
session.setPlaybackState(new PlaybackStateCompat.Builder()
        .setState(PlaybackStateCompat.STATE_PLAYING, 0, 1.0f)
        .build());

session.setActive(true);

// The media router tries to bind its own VolumeProvider which kinda
// works. We need to unbind the one provided and put ours in.
router.setMediaSessionCompat(session);
session.setPlaybackToRemote(new RemoteVolume(myRemoteRoute));
0xcaff
  • 13,085
  • 5
  • 47
  • 55
  • On using volume keys onAdjustVolume is called with delta 0 any idea why? when changing volume using cast dialog this works fine – ingsaurabh May 28 '17 at 15:12
  • It might be called to update the current volume. Is it happening more than once? – 0xcaff May 28 '17 at 18:16
  • Also, `STEPS` should be non-zero. – 0xcaff May 28 '17 at 18:18
  • step is not zero, and its called only once per volume click event which is fine I think. only delta is 0 which is wrong – ingsaurabh May 29 '17 at 06:06
  • Ok now its working but now its called twice with correct delta and second time with value 0, and this volume is not in sync with cast dialog volume, delta 0 I can handle using a simple check, so any idea about volume sync problem also if I change the volume using cast dialog and reopens the dialog then slider is reset to default value? – ingsaurabh Jun 05 '17 at 16:43