Android Question still unable to work car media button

apti

Member
I have been scrambling through the forum for 2 weeks trying to find a way to do something that every other app seems to be able to do.

I have tried multiple solutions with no help. questions go unanswered.

I am attempting to act on media buttons in the car from a service in b4x. Can somebody tell me a library that works for this or how to do this?
 

b4x-de

Active Member
Licensed User
Longtime User
If the forum does not provide an answer for you, you might have asked ChatGPT? To me it says:

You can make your B4A app respond to Play, Pause, Next, etc., sent from a car’s media controls over Bluetooth. The car uses AVRCP (Audio/Video Remote Control Profile), and Android can automatically route those commands to your app if it uses a properly configured MediaSession.


---

How to Do It in B4A

B4A doesn’t offer direct MediaSession support, but you can still use it via JavaObject and Inline Java. Here's the outline:


---

1. Create a MediaSession

Dim mediaSession As JavaObject
mediaSession.InitializeNewInstance("android.support.v4.media.session.MediaSessionCompat", _
Array As Object(Activity, "MyMediaSession"))
mediaSession.RunMethod("setFlags", Array(Bit.Or(1, 2))) ' HANDLE_MEDIA_BUTTONS | HANDLE_TRANSPORT_CONTROLS
mediaSession.RunMethod("setActive", Array(True))


---

2. Set Playback State

Dim psBuilder As JavaObject
psBuilder.InitializeNewInstance("android.support.v4.media.session.PlaybackStateCompat$Builder", Null)

Dim actions As Long = Bit.Or(PlaybackStateCompat.ACTION_PLAY, PlaybackStateCompat.ACTION_PAUSE)
psBuilder.RunMethod("setActions", Array(actions))
psBuilder.RunMethod("setState", Array(PlaybackStateCompat.STATE_PAUSED, 0L, 1.0f))

Dim playbackState As JavaObject = psBuilder.RunMethod("build", Null)
mediaSession.RunMethod("setPlaybackState", Array(playbackState))

> Note: You'll need to define those constants manually or via inline Java.




---

3. Set Callback for Media Events (Play, Pause, etc.)

You’ll need to write a small Java class in Inline Java:

#If JAVA
import android.support.v4.media.session.MediaSessionCompat;

public static class MyCallback extends MediaSessionCompat.Callback {
@override
public void onPlay() {
BA.Log("Play command received from car");
}

@override
public void onPause() {
BA.Log("Pause command received from car");
}

@override
public void onSkipToNext() {
BA.Log("Next track");
}
}
#End If

Then set the callback:

Dim callback As JavaObject
callback.InitializeNewInstance("your.package.name.main$MyCallback", Null)
mediaSession.RunMethod("setCallback", Array(callback))


---

4. (Optional) Set Metadata

This improves display in car UIs:

Dim metadataBuilder As JavaObject
metadataBuilder.InitializeNewInstance("android.support.v4.media.MediaMetadataCompat$Builder", Null)
metadataBuilder.RunMethod("putString", Array("android.media.metadata.TITLE", "Track Title"))
metadataBuilder.RunMethod("putString", Array("android.media.metadata.ARTIST", "Artist Name"))

Dim metadata As JavaObject = metadataBuilder.RunMethod("build", Null)
mediaSession.RunMethod("setMetadata", Array(metadata))


---

Conclusion

Yes, your B4A app can be controlled from a car’s media system:

Use MediaSessionCompat via JavaObject

Set playback state and media actions

Register callbacks using Inline Java

(Optionally) Add metadata for better UI integration
 
Upvote 0

apti

Member
I will give this a try, but I do not do java so when it comes to that I will not know when or if something is wrong. As for the AI's I have wasted many days with various solutions provided by AI and most of the time they like to use events and methods and objects that do not exist so was very frustrating. Since nothing has helped I will try this over the next couple days and see what it does. Thank you in advance.
 
Upvote 0

apti

Member
well, working on this and already issues. It says I should define the constants, but it never tells me what they should be defined as. This is the problem. I may be an experienced programmer but b4x is still new to me and regardless of language, it is tough to define a constant when you do not know what it should be defined as. Kinda makes the program tough to write that way. Typical of AI in that it is not really AI it is just enhanced web search and often what it returns is useless. At the moment until I know what the constants should be, I can't do anything
 
Upvote 0

apti

Member
I would say the constants it refers to are below right in the code you gave. I put it below so you can see. I highlighted the line that says the constants need to be defined. Try to keep in mind that not everybody knows java. I for one never used java so java examples are not easy to follow. logic can be followed but syntax can't and that is the important part here. Since you generated the code from A.I. I will not hold my breath that it will work. Not had any luck with any AI to help with this. Have tried correcting AI but it is too stupid to learn. Keeps giving same bad code. But can't test this out until I know what the constants need to be. what values.

2. Set Playback State
your code:
2. Set Playback State

Dim psBuilder As JavaObject
psBuilder.InitializeNewInstance("android.support.v4.media.session.PlaybackStateCompat$Builder", Null)

Dim actions As Long = Bit.Or(PlaybackStateCompat.ACTION_PLAY, PlaybackStateCompat.ACTION_PAUSE)
psBuilder.RunMethod("setActions", Array(actions))
psBuilder.RunMethod("setState", Array(PlaybackStateCompat.STATE_PAUSED, 0L, 1.0f))

Dim playbackState As JavaObject = psBuilder.RunMethod("build", Null)
mediaSession.RunMethod("setPlaybackState", Array(playbackState))

> Note: You'll need to define those constants manually or via inline Java.
 
Upvote 0

apti

Member
If the forum does not provide an answer for you, you might have asked ChatGPT? To me it says:

You can make your B4A app respond to Play, Pause, Next, etc., sent from a car’s media controls over Bluetooth. The car uses AVRCP (Audio/Video Remote Control Profile), and Android can automatically route those commands to your app if it uses a properly configured MediaSession.


---

How to Do It in B4A

B4A doesn’t offer direct MediaSession support, but you can still use it via JavaObject and Inline Java. Here's the outline:


---

1. Create a MediaSession

Dim mediaSession As JavaObject
mediaSession.InitializeNewInstance("android.support.v4.media.session.MediaSessionCompat", _
Array As Object(Activity, "MyMediaSession"))
mediaSession.RunMethod("setFlags", Array(Bit.Or(1, 2))) ' HANDLE_MEDIA_BUTTONS | HANDLE_TRANSPORT_CONTROLS
mediaSession.RunMethod("setActive", Array(True))


---

2. Set Playback State

Dim psBuilder As JavaObject
psBuilder.InitializeNewInstance("android.support.v4.media.session.PlaybackStateCompat$Builder", Null)

Dim actions As Long = Bit.Or(PlaybackStateCompat.ACTION_PLAY, PlaybackStateCompat.ACTION_PAUSE)
psBuilder.RunMethod("setActions", Array(actions))
psBuilder.RunMethod("setState", Array(PlaybackStateCompat.STATE_PAUSED, 0L, 1.0f))

Dim playbackState As JavaObject = psBuilder.RunMethod("build", Null)
mediaSession.RunMethod("setPlaybackState", Array(playbackState))

> Note: You'll need to define those constants manually or via inline Java.




---

3. Set Callback for Media Events (Play, Pause, etc.)

You’ll need to write a small Java class in Inline Java:

#If JAVA
import android.support.v4.media.session.MediaSessionCompat;

public static class MyCallback extends MediaSessionCompat.Callback {
@override
public void onPlay() {
BA.Log("Play command received from car");
}

@override
public void onPause() {
BA.Log("Pause command received from car");
}

@override
public void onSkipToNext() {
BA.Log("Next track");
}
}
#End If

Then set the callback:

Dim callback As JavaObject
callback.InitializeNewInstance("your.package.name.main$MyCallback", Null)
mediaSession.RunMethod("setCallback", Array(callback))


---

4. (Optional) Set Metadata

This improves display in car UIs:

Dim metadataBuilder As JavaObject
metadataBuilder.InitializeNewInstance("android.support.v4.media.MediaMetadataCompat$Builder", Null)
metadataBuilder.RunMethod("putString", Array("android.media.metadata.TITLE", "Track Title"))
metadataBuilder.RunMethod("putString", Array("android.media.metadata.ARTIST", "Artist Name"))

Dim metadata As JavaObject = metadataBuilder.RunMethod("build", Null)
mediaSession.RunMethod("setMetadata", Array(metadata))


---

Conclusion

Yes, your B4A app can be controlled from a car’s media system:

Use MediaSessionCompat via JavaObject

Set playback state and media actions

Register callbacks using Inline Java

(Optionally) Add metadata for better UI integration
this is why I do not like AI... this line
psBuilder.RunMethod("setState", Array(PlaybackStateCompat.STATE_PAUSED, 0L, 1.0f))
is not in correct format yet your AI says it is fine. I put this line in and the IDE tells me there is an error in it. No idea what the correct format is but this is not it. and this is early in. That is why I asked people that should be able to help instead of trying AI. AI never gets coding correct. I wasted a week on AI for this and got nowhere.

Is there anybody here that has a library for this? or has working code that I can see? Please no A.I. generated stuff as it never works.
 
Upvote 0

b4x-de

Active Member
Licensed User
Longtime User
Of course you can complain about everything the AI does wrong. But complaining won't get you anywhere. Just show us what you've already done. Upload your project and post the log of the error message. That way we can help you.
 
Upvote 0

apti

Member
I have been trying to make the example work but the AI (yes complaining about that again) gives this line...

psBuilder.RunMethod("setState", Array(PlaybackStateCompat.STATE_PAUSED, 0L, 1.0f))

which produces an error in the IDE that the array format is incorrect. No point posting other stuff when the example is still the problem. I expect that if you take the example and try to run it you will see the problem clear as day.
 
Upvote 0

Pendrush

Well-Known Member
Licensed User
Longtime User
You need few things:
1. Media session id created by Media3/Exoplayer. Link : https://developer.android.com/media/media3/session/background-playback
2. Change manifest file to set media button. Link: https://developer.android.com/reference/androidx/media/session/MediaButtonReceiver
3. Create events for buttons (play, pause, play/pause, next, previous).

If this is not already implemented in Media3/Exoplayer wrapper, then you will need to add all of this with JavaObject.

This is media button implementation in Kotlin if this can help you in any way:

Java:
override fun onMediaButtonEvent(session: MediaSession, controllerInfo: MediaSession.ControllerInfo, intent: Intent): Boolean {
        val keyCode =
            if (Build.VERSION.SDK_INT > 33) {
                intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT, KeyEvent::class.java)?.keyCode
            } else {
                @Suppress("DEPRECATION")
                intent.getParcelableExtra<KeyEvent>(Intent.EXTRA_KEY_EVENT)?.keyCode
            }
        val keyAction =
            if (Build.VERSION.SDK_INT > 33) {
                intent.getParcelableExtra(Intent.EXTRA_KEY_EVENT, KeyEvent::class.java)?.action
            } else {
                @Suppress("DEPRECATION")
                intent.getParcelableExtra<KeyEvent>(Intent.EXTRA_KEY_EVENT)?.action
            }

        if (keyAction == KeyEvent.ACTION_DOWN) {
            when (keyCode) {
                KeyEvent.KEYCODE_MEDIA_NEXT -> {
                   Timber.i("KEYCODE_MEDIA_NEXT")   
                }

                KeyEvent.KEYCODE_MEDIA_PREVIOUS -> {
                    Timber.i("KEYCODE_MEDIA_PREVIOUS")                  
                }

                KeyEvent.KEYCODE_MEDIA_PAUSE -> {
                    Timber.i("KEYCODE_MEDIA_PAUSE")
                }

                KeyEvent.KEYCODE_MEDIA_PLAY -> {
                    Timber.i("KEYCODE_MEDIA_PLAY")
                }

                KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE -> {
                    Timber.i("KEYCODE_MEDIA_PLAY_PAUSE")
                }
            }
        }
        return super.onMediaButtonEvent(session, controllerInfo, intent)
    }
})
.setSessionActivity(pendingIntent())
.setPeriodicPositionUpdateEnabled(false)
.setCustomLayout(commandList)
.build()
}
 
Last edited:
Upvote 0
Top