AudioExoPlayer a simple player with great potential

🏃‍♂️ AudioExoPlayer

An extension for MIT App Inventor 2.

:memo: Specifications


:package: Package: pl.patryk_f.exoplayer
:floppy_disk: Size: 2,50 MB
:gear: Version: 2.1
:iphone: Minimum API Level: 21
:date: Updated On: 2025-10-02T22:00:00Z
:link: Help URL: Learn more
:computer: Built & documented using: FAST v5.2.0-premium


:handshake: Multi-Components

  1. AudioExoPlayer
  2. PlayerView

:jigsaw: AudioExoPlayer

Audio player based on the ExoPlayer library. Developed by Patryk F. by Fast.

Events:

AudioExoPlayer has total 5 events.

1. Looped

Looped_Event

This event fires when loop has been triggered

2. SourceLoaded

SourceLoaded_Event

This event fires when source has been loaded and is ready to play

3. Completed

Completed_Event

This event indicates, that media has reached the end

4. OnError

OnError_Event

An event triggered when an error occurs in the player. The block returns the error number, the error name, and a message describing the error.

Parameter Type
errorNumber number
errorName text
message text

5. AudioFocusChanged

AudioFocusChanged

Triggered when audio focus changes

Parameter Type
focusLoss boolean

Methods:

AudioExoPlayer has total 5 methods.

1. SeekTo

SeekTo_Call_Method

Start at a given position. Precondition: player must be in status PLAYING or PAUSED and position must be < duration.

Parameter Type
position number

2. Play

Play_Call_Method

Start from the beginning. If the player is in status PAUSED, the playing is resumed.

3. Pause

Pause_Call_Method

Pauses the player. Player must be in status PLAYING.

4. Stop

Stop_Call_Method

Stops the player and sets the current position to the beginning. Player must be in status PLAYING, PREPARED or PAUSED.

5. FormatTime

FormatTime_Get_Method

Converts duration in milliseconds to human-readable time in hours, minutes, and seconds.

  • Return type: text
Parameter Type
millis number

Setters:

AudioExoPlayer has total 4 setter properties.

1. Source

Source_Set_Property

Set the audio source. Local file paths, server file urls, and uris are accepted.

  • Input type: text
  • Helper type: asset

2. Loop

Loop_Set_Property

If true, the Player will loop when it plays. Setting Loop while the player is playing will affect the current playing.

  • Input type: boolean

3. PlayOnlyInForeground

PlayOnlyInForeground_Set_Property

If true, the Player will pause playing when leaving the current screen; if false (default option), the Player continues playing whenever the current screen is displaying or not.

  • Input type: boolean

4. Volume

Volume_Set_Property

Sets the volume to a number between 0 and 100

  • Input type: number

5. MultiScreen

MultiScreen_Set_Property

Allows the player to play on multiple screens.

  • Input type: boolean

Getters:

AudioExoPlayer has total 7 getter properties.

1. Source

Source_Get_Property

Get the audio source.

  • Return type: text

2. IsPlaying

IsPlaying_Get_Property

Returns information about whether the player is currently playing.

  • Return type: boolean

3. Loop

Loop_Get_Property

Returns true if the Player will loop when it plays; false otherwise.

  • Return type: boolean

4. PlayOnlyInForeground

PlayOnlyInForeground_Get_Property

Returns true if the Player will pause playing when leaving the current screen; false otherwise.

  • Return type: boolean

5. Volume

Volume_Get_Property

Gets the volume as a number between 0 and 100

  • Return type: number

6. Duration

Duration_Get_Property

Returns the duration of the current media item in milliseconds, or 0 if the duration is not known.

  • Return type: number

7. CurrentPosition

CurrentPosition_Get_Property

Returns the playback current position in milliseconds.

  • Return type: number

:jigsaw: PlayerView

A module that extends the capabilities of AudioExoPlayer, allowing you to create a player view with the necessary controls. Developed by Patryk F. by Fast.

Event:

PlayerView has total 1 event.

1. FullScreenButtonClicked

Triggered when fullscreen button is clicked.

FullScreenButtonClicked

Methods:

PlayerView has total 5 methods.

1. InitializePlayer

InitializePlayer

Initializes the player view within the given container for the given player. We can also specify the type of surface to render video, or disable the surface for audio sources.

Parameter Type
container component
player component
renderingSurfaces RenderingSurfaces (helper blocks)
  • Enums for RenderingSurfaces: None, SurfaceView, TextureView, SphericalView, VideoDecoderGlSurfaceView

2. SetControllerAutoHide

SetControllerAutoHide

Sets the playback controls timeout. The playback controls are automatically hidden after this duration of time has elapsed without user input and with playback or buffering in progress.

Parameter Type
timeoutMs number

3. ShowCustomErrorMessage

ShowCustomErrorMessage

Sets a custom error message to be displayed by the view. The error message will be displayed permanently, unless it is cleared by passing epty string to this method.

Parameter Type
errorMessage text

4. HideController

HideController

Hides the playback controls.

5. ShowController

ShowController

Shows the playback controls.

Setters:

PlayerView has total 20 setter properties.

1. ShowBuffering

ShowBuffering

Sets whether a buffering spinner is displayed when the player is in the buffering state. The buffering spinner is not displayed by default.

  • Input type: ShowBuffering
  • Helper type: ShowBuffering
  • Helper enums: Never, WhenPlaying, Always

2. ControllerAutoShow

ControllerAutoShow

Sets whether the playback controls are automatically shown when playback starts, pauses, ends, or fails.

  • Input type: boolean

3. ControllerHideOnTouch

ControllerHideOnTouch

Sets whether the playback controls are hidden by touch events.

  • Input type: boolean

4. ControllerShowTimeoutMs

ControllerShowTimeoutMs

Sets the playback controls timeout. The playback controls are automatically hidden after this duration of time has elapsed without user input and with playback or buffering in progress.

  • Input type: number

5. ControllerAnimation

ControllerAnimation

Set if the controller should show/hide with animation.

  • Input type: boolean

6. ShowFullScreenButton

ShowFullScreenButton

Sets the visibility of the full screen button.

  • Input type: boolean

7. SetFullScreenState

SetFullScreenState

Sets whether the player is currently in fullscreen, this will change the displayed icon.

  • Input type: boolean

8. ShowFastForwardButton

ShowFastForwardButton

Sets the visibility of the fast forward button.

  • Input type: boolean

9. ShowRewindButton

ShowRewindButton

Sets the visibility of the rewind button.

  • Input type: boolean

10. ShowNextButton

ShowNextButton

Sets the visibility of the next button.

  • Input type: boolean

11. ShowPreviousButton

ShowPreviousButton

Sets the visibility of the previous button.

  • Input type: boolean

12. ShowShuffleButton

ShowShuffleButton

Sets the visibility of the play button.

  • Input type: boolean

13. ShowRepeatButton

ShowRepeatButton

Sets the visibility of the given repeat button.

  • Input type: RepeatMode
  • Helper type: RepeatMode
  • Helper enums: Off, One, All

14. ResizeMode

ResizeMode

Sets the resize mode for the video view.

  • Input type: ResizeMode
  • Helper type: ResizeMode
  • Helper enums: Fit, FixedWidth, FixedHeight, Fill, Zoom

15. ShowSubtitleButton

ShowSubtitleButton

Sets the visibility of the subtitle button.

  • Input type: boolean

16. ShutterBackgroundColor

ShutterBackgroundColor

Sets the background color of the shutter view.

  • Input type: number

17. TimeBarScrubbingEnabled

TimeBarScrubbingEnabled

Sets whether the time bar should seek immediately as the user drags the scrubber around (true), or only seek when the user releases the scrubber (false).

  • Input type: boolean

18. UseController

UseController

Sets whether the playback controls can be shown. If set to false the playback controls are never visible and are disconnected from the player.

  • Input type: boolean

19. ArtworkDisplayMode

ArtworkDisplayMode

Sets whether and how artwork is displayed if present in the media.

  • Input type: ArtworkDisplayMode
  • Helper type: ArtworkDisplayMode
  • Helper enums: Off, Fit, Fill

20. DefaultArtwork

DefaultArtwork

Sets the default artwork to display if ArtworkDisplayMode is Fit or Fill and no artwork is present in the media.

  • Input type: text

Getters:

PlayerView has total 6 getter properties.

1. ControllerAutoShow

ControllerAutoShow

Returns whether the playback controls are automatically shown.

  • Return type: boolean

2. ControllerHideOnTouch

ControllerHideOnTouch

Returns whether the playback controls are hidden by touch events.

  • Return type: boolean

3. ControllerShowTimeoutMs

ControllerShowTimeoutMs

Return the playback controls timeout. The playback controls are automatically hidden after this duration of time has elapsed without user input and with playback or buffering in progress.

  • Return type: number

4. ResizeMode

ResizeMode

Get the resize mode for the video view.

  • Return type: ResizeMode

5. UseController

UseController

Returns whether the playback controls can be shown.

  • Return type: boolean

6. IsControllerFullyVisible

IsControllerFullyVisible

Returns whether the playback controls are fully visible.

  • Return type: boolean

:new: Release notes


Show

v1.0:

  • basic version

v1.1:

  • added support for multi-screen playback (MultiScreen property block)

v1.2:

  • update to the latest version of the Media3-1.8.0 library

v1.3:

  • fixed stream playback error (HTTP 403) by setting proper User-Agent header

v2.0

  • added AudioFocusChanged event
  • added PlayerView component
  • fixed error reporting in the OnError event

v2.1

  • fixed AudioFocusChanged event

:file_folder: Download


Extensions:

Older version

Example: ExoPlayerTest2 (5).aia (2.2 MB)

6 Likes

Great! :clap:
I and many others have been waiting for this for a long time. Besides the fact that AudioExoPlayer accepts and plays all streaming formats (including AAC+), it also allows audio tracks to be looped seamlessly (at least for loopable audio formats like OGG and WAV).

I'll have to test whether it also works with MP3. In particular, I have to test it with all common audio formats (especially OGG and WAV, but also MP3, AAC, M4A) on critical Chinese devices (Xiaomi, Huawei, OnePlus, Oppo), where looping with TaifunPlayer (with OGG) unfortunately occasionally causes problems.

Very nice.

Possible to turn off music in a different screen to the one that the music was started in ?

I did this once with the standard Media Player, so I think I can add this feature here.
This will probably be the weight of an additional block added in the event of opening the next screen.

You sent me a test app with the AudioExoPlayer in December 2024:

grafik

So your great extension lay unnoticed in the basement for exactly 10 months. :wink: :upside_down_face:
(The delay was apparently due to problems uploading extensions with AI2 at that time.)

grafik

I don't see any differences between the two versions, except for the compilation date. Is there one?

It also loops MP3 well.

1 Like

Probably nothing has changed. To be honest, I don't remember what was included in that version. I definitely need to update the ExoPlayer library, as this one is 1.4.1. I'm thinking of adding events to return the current player status.

1 Like

I remember us talking about this before. Over the past 12 years, I've probably run 1,000 tests on dozens of devices and all relevant Android versions to test seamless looping, as it's essential for most of my apps. And I've always been surprised by the problems I encountered on certain devices. Some manufacturers massively interfere with audio modulation. With the OnePlus 6, for example, I noticed that the volume of short audio tracks (< 5 seconds) is increased. On other devices (I don't remember exactly which ones), the audio tracks had to be a certain minimum length (> 20 seconds) for seamless looping. The tests were conducted with TaifunPlayer. As far as I remember, there were no problems with Kodular's ExoPlayer. Except, of course, that it stops after a short time in the background (idle mode).


In short, I have to test it myself! :wink:

I added the ability to play on multiple screens.

Now the extension is based on the latest version of the Media3-1.8.0 library

1 Like

Does that mean one can start the music on one screen and then be able to stop the music on a different screen? (PlayOnlyInForeground=true/false)

1 Like

When you set the MultiScreen property to true, you will be able to control the player running on screen1, for example, from screen2.

PlayOnlyInForeground = true, then the player stops playing when the application goes to the background.

3 Likes

Version 1.3, fixed an issue with some streaming services reporting a 403 error.

3 Likes

Hello @Patryk_F,

I have encountered what I think is an issue when a project has more than one instance of AudioExoPlayer. If the Source of one player is set to a bad URL, a Playback error occurs, but the AudioExoPlayer.OnError event is not called.

Here are the particulars of the test case I am looking at:

Designer with extra AudioExoPlayer added but otherwise unreferenced:

The blocks, which set a bad URL (KDFC trucated):

"https://18243.live.streamtheworld.com:443/KDFCFMAAC96_"


Excerpt of logcat output showing the Playback error which does not cause  OnError event to be called

...  E ExoPlayerImplInternal: Playback error
 ...  E ExoPlayerImplInternal:   androidx.media3.exoplayer.w: Source error
 ...  E ExoPlayerImplInternal:       at androidx.media3.exoplayer.G.a(Unknown Source:16)
 ...  E ExoPlayerImplInternal:       at androidx.media3.exoplayer.G.handleMessage(Unknown Source:3175)
 ...  E ExoPlayerImplInternal:       at android.os.Handler.dispatchMessage(Handler.java:108)
 ...  E ExoPlayerImplInternal:       at android.os.Looper.loopOnce(Looper.java:268)
 ...  E ExoPlayerImplInternal:       at android.os.Looper.loop(Looper.java:384)
 ...  E ExoPlayerImplInternal:       at android.os.HandlerThread.run(HandlerThread.java:103)
 ...  E ExoPlayerImplInternal:   Caused by: pl.patryk_f.exoplayer.repacked.dk: Response code: 403
 ...  E ExoPlayerImplInternal:       at pl.patryk_f.exoplayer.repacked.da.a(Unknown Source:530)
 ...  E ExoPlayerImplInternal:       at pl.patryk_f.exoplayer.repacked.dp.a(Unknown Source:12)
 ...  E ExoPlayerImplInternal:       at pl.patryk_f.exoplayer.repacked.jj.f(Unknown Source:27)
 ...  E ExoPlayerImplInternal:       at pl.patryk_f.exoplayer.repacked.lF.run(Unknown Source:45)
 ...  E ExoPlayerImplInternal:       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1156)
 ...  E ExoPlayerImplInternal:       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:651)
 ...  E ExoPlayerImplInternal:       at java.lang.Thread.run(Thread.java:1119)

UIExoPlayer_Error.aia (6.2 MB)

I realize that having two instances of the player would be unusual :slight_smile: but I do have one project which does.

Perhaps I have mis-coded something ... but if you remove the second player, the OnError event is called.

Thanks for taking a look,
Randal

I have located the problem, it will be fixed in the next update

1 Like

Thanks!

Also I have a feature request for your consideration: add an OtherPlayerStarted event.

The project in which that I first encountered the above missing Playback error is one which has two players that respond to OtherPlayerStarted :slight_smile:

Kind regards,
Randal

I don't know if this will be possible. I see that Player has such an event, but it's inactive from what I can see. I'll see what can be done. What do you plan to use this event for?

Here is a test app that has two Player components set to play the same mp3 file (looped) at different volume levels.

When you start one player while the other is running, it will stop itself and update the status using the OtherPlayerStarted event... seems to work for me.

OtherPlayer_Test.aia (4.1 MB)

My app has a Player running in an Itoo service (background) that is sourced to a live audio stream of an event (eg., a sports event). By manually (using UI buttons) pausing and restarting the Player it can be adjusted to be synchronized with a live video stream (on a different device) of the same event.

But if another app starts (or a phone call comes in) it could pause/stop the Player - thus making it out of sync with the video. :frowning:

I am hoping to be able to detect this and and possibly just restart and mute my player to retain the sync... but this may not work... I have yet to demonstrate it with the standard Player component...but that is the idea.

I have an alternative in mind if this is not possible ...

Thanks for checking into it.

Kind regards,
Randal

So I think you need focus management, not necessarily an event when another player starts. I think you can set the focus so it doesn't react to other players.

Hmmm... Maybe I don't understand what you are suggesting ...

The user interface (Screen1) of my app does not remain active. Once the player is launched (by a service/process created by Itoo Open Source • Background Tasks: Itoo 🚀 ) the user interface can be exited and the app plays from the background while other apps are active... so I am not sure what focus should be maintained... What am I missing?

-Randal