I am developing an application which supports GoogleCast. I am using a CastCompanionLibrary and everything works fine, but there is one little problem there in my application.
I need to change the layout, which appears in case that user changes the volume via HW buttons. In my application, there the layout looks like this:
There is a Cast icon in this layout, but it is white and visibility of them is very bad. For example, in YouTube application, there the same layout looks like this:
So, my question is simple: how can I change the layout, or how can I change the Cast icon in layout? I do not see it in CastCompanionLibrary.
Thanks for any advice.
As far as I know, the UI that you see there when you change the volume is provided by the system through MediaSession or RemoteControlClient, etc and not the application itself. As a result, I am not aware of any way to change that. The UI that you see in YT is a custom UI, and handling of the volume is done through app; in fact if you send the YT app to background and change the volume, you see a different UI so they seem to have decided to capture hardware volume themselves and provide their own custom UI. This is doable as long as your app is in front; as soon as it loses focus (for example when it goes to background), your app doesn't receive the volume key events and your app cannot do much (that is what happens to YT as well). Try Google Play Music and see how their UI looks like when you change volume while casting.
In order to achieve this, the player service must maintain an "active" MediaSessionCompat. The service should proactively sync media player's playback state with the MediaSessionCompat. In addition to this, service must call MediaRouter#setMediaSessionCompat() with the media session on its initialization.
If all of these conditions are met, then whilst casting, the service can call MediaSessionCompat#setPlaybackToRemote(VolumeProviderCompat). Then whenever the player is in "playing" state, volume events will be delivered to MediaSession which calls the VolumeProviderCompat. To switch back to regular media controls, i.e. on cast session end, the service can call MediaSessionCompat#setPlaybackToLocal(AudioManager.STREAM_*).
Sample implementation - Android MediaRouter Volume events
Related
I want to use the media buttons to control a foreground app, but not for audio use.
So the goal is to detect button clicks to do certain things in the app.
I can achieve that by using MediaSession and the MediaButtonReceiver. see here
The problem is that when the app is used, often users play music in the background, so the audio focus of the background app takes over the MediaSession and i cannot control my app anymore.
Is there a way to achieve that? Directly listening for button clicks with onKeyDown does not seem to work.
sadly there is no way for two active MediaSessions at the same time. if another app is playing music and run MediaSession then yours doesn't have focus and isn't active... this is made for purpose - better UX - only one "player" app can play music (or video). if this wouldn't work like that and you could play music by few apps at once then how should work media button on e.g. headphones? pasuing/resuming all players? this is just not user-friendly, so Android team introduced MediaSession pattern with option for calling "focus on me now" by any app, but then another app/MediaSession pauses and doesn't get any inputs (this active session does)
if you need physical buttons presses then onKeyDown should work (inside Activity or eventually using AccessibilityService, which would work "globally" in whole system). if you need some on-screen notification buttons presses then just make custom layout for your notification with as much buttons as you like, even styled as a player
note that in Android 11 active MediaSessions notification is stickied to top of notification section when you drop down status bar. your custom notification will be somewhere below between all others (you can manipulate position a bit using priority param for notification/channel)
My HTML5 game has some background music that uses Howler.js in "html5" mode, which apparently triggers Chrome for Android's media playback notifications. This means a notification appears while the user has my game open in any tab:
The game is a good citizen and pauses the music while the tab is not in focus, so there is no need for this notification. It's even actively confusing, because the user can pause and resume the game's background music without being in the game. But I can't find a way to get rid of the notification.
I tried calling stop() instead of pause() or mute() on the music object, but this doesn't remove the notification.
Looking a bit deeper, I discovered the experimental MediaSession API (W3C draft) which supposedly can be used to control the notification. But, if I understand correctly, it offers no way to disable it outright!
I tried this at the start of my application:
if (typeof navigator.mediaSession == 'object') {
navigator.mediaSession.playbackState = 'none'
}
However, this only sets the declared playback state (in spec terminology). And setting that to 'none' has no effect:
The actual playback state is computed in the following way:
If the declared playback state is "playing", return "playing".
Otherwise, return the guessed playback state.
And the guessed playback state is something I have no control over; it's derived by the browser based on the state of <audio> elements on the page.
Is there a possibility that I'm overlooking, or is this just an oversight in the current MediaSession specification?
This may be what you are looking for.
If you can make the music loop within 5 second (like in NES days), notification won't show it said.
Else, use Web Audio API without "audio" element. So, use a stream.
Otherwise, "Dismiss media notifications with audio.src = ''." reference
I am trying to understand what each of these two Android constructs actually are and of course how they work, especially the transport controls, when dealing with the MediaPlayer and the MediaSession classes.
From the official documentation about the MediaSession, it
Allows interaction with media controllers, volume keys, media buttons, and transport controls.
As far as I understood, the media buttons refers to actual physical buttons on a device (if existent) or for ex. on a Bluetooth headset. Volume keys are obvious.
When comes to the media controllers I think I managed to figure out that it refers to a particular View, the FrameView that has buttons for play/pause as well as skip next/previous etc. But what exactly are the transport controls then, where can/should they be used and how are they implemented in code?
Thank you in advance for any answers!
For future reference for myself or others, the MediaPlayer is essentially like the internal mechanism of a stereo player, and directly controls the sound playback, "internally". You do have functions on it, like play(), pause(), skipToNext(), etc.
When you want to create a music application, you'd normally implement a client-service model, with the app interface being your client (in the main UI thread), and the service will play the music (also in the background). What Google did was implement a client-service model specifically for music and video, the MediaSession(Compat). It has its own type of service, session states (when you want to have Notifications, Android Wear or Auto, so they know if the app is playing or paused, can get the track information and album image, etc. so that everything is well synchronized on all these platforms), and the MediaController and its callbacks that need to be implemented for different functionality.
One of its options is to getTransportControls(), which essentially are a high-level representation of what happens when you'd press the play(), pause(), etc. buttons on that stereo player mentioned earlier. For each of these you #Override their respective onPlay(), onPause() callback methods to do the exact functionality you want on that MediaPlayer object that controls your music. In here is where you'd then call the MediaPlayer.play() functions, as well as setting the playback state of MediaSession, possibly update the notification, etc.
As for the others, volume keys are indeed the volume keys, and the Media Buttons are indeed physical buttons you might have (Bluetooth headset, earphones with playback buttons, etc.) that you can set up your app so it recognizes and makes use of them.
For whoever is interested to see this better in action, below is the repo of my app project. Although far from a fully-featured, bug-free app, it does implement the MediaSession and the Service, plus notifications and MediaButton controls pretty much perfectly.
https://github.com/RockBoyEmy/GESMediaPlayer
thanks also to #pantos27 for his help
I want to initiate my activity anytime using Volume up/down hardware button.
I tried in some links but no use.
And also i want to know how to use service for this.
Thanks in advance..
This is not possible on Android. The Volume Buttons can't be monitored or accessed by your app unless it is the current foreground app (i.e. you have an Activity visible and in use on the screen).
An alternative could be to listen for device shake motion and start then.
Is it possible to register a listener to listen for changes in the volume level of the music stream in Android?
I'm displaying the actual volume in a SeekBar and I would like to change the seekbar if the user changes the volume with the hardware volume keys. At the moment the correct volume is displayed until the user changes the volume with hardware keys.
This is not a perfect answer but a hack:
android.media.VOLUME_CHANGED_ACTION
I found above action in native logs while changing volume via hard volume key.
01-25 16:11:24.015: DEBUG/VolumePanel(189): onVolumeChanged(streamType: 2, flags: 4)
01-25 16:11:24.015: DEBUG/BluetoothA2dpService(189): Received intent with action: android.media.VOLUME_CHANGED_ACTION
so go ahead and register BroadcastReceiver with action "android.media.VOLUME_CHANGED_ACTION" if you don't have any other solution.
Other way of doing is;
Taking over the volume key on Android .
One option would be to use registerMediaButtonEventReceiver and have your application handle the hardware keys. You could adjust the volume seekbar in your app and use AudioManager to adjust the volume.
Another possibility would be to create a service in your app that runs in the background and periodically checks the volume and adjusts your seekbar accordingly.
You can display the volume by accessing the current volume from AudioManger if your app is currently in focus. Otherwise, there is no concrete way (official way using api) of doing this.
Android recommends letting the system do all of this for you by calling setVolumeControlStream(). This will bring up a volume seekbar for the audio stream that your app is using whenever the user tries to adjust the volume with their hardware buttons.
"You may be tempted to try and listen for volume key presses and modify the volume of your audio stream that way. Resist the urge. Android provides the handy setVolumeControlStream() method to direct volume key presses to the audio stream you specify.
Having identified the audio stream your application will be using, you should set it as the volume stream target. You should make this call early in your app’s lifecycle—because you only need to call it once during the activity lifecycle, you should typically call it within the onCreate() method (of the Activity or Fragment that controls your media). This ensures that whenever your app is visible, the volume controls function as the user expects.
setVolumeControlStream(AudioManager.STREAM_MUSIC);
From this point onwards, pressing the volume keys on the device affect the audio stream you specify (in this case “music”) whenever the target activity or fragment is visible."
From: http://developer.android.com/training/managing-audio/volume-playback.html
I've faced a similar issue.
The app should show a volume off indicator in case of Media Sound has turned off during the video playback. This approach handles cases when the user changes Media level by swipe too.
So, wrote a simple Rx wrapper for ContentObserver which observes Media Sound level directly ))
Gist link here