Audio Player Tutorial

Hi guys

I have been creating a audio reader from scratch, and after days of struggle, I made it work.
There was some obstacles on the way. I didn’t find any guide to do it, and I was only able to make after geting little pieces of information together from the forum.
I am no coder nor developper, and I kind of regret that I am the one to do this tutorial, but I hope it will help others, for whom, like me, it was not an obvious task.
May be there are better way, or different ways to do, I don’t know, but here is how I made it.

CapturePlayer

  1. Upload the track you want to play somewhere on the internet, accessible with an URL,wheter on your CMS, on Firebase…

  2. Buttons Play / Pause / Stop :
    -We want the button play to change into a Pause icon when pressed.
    -I also wanted a Stop icon, to reset the track, and I wanted it to appear only when the track is playing.

The Play Icon:
Here is the logic

  • Create a page variable, called for example form_icon, and in the assigned value, choose Static Icon.
  • The IF formula will filter whether the icon is currently a play icon : IS_EQUAL(pageVars.form_icon, “play”)

If that condition is filled it will set the page variable form_icon to “Pause”, and start the audio, and set the page variable visible to true (so that the stop button appears).
Use the Start/Resume audio playback, that you can find in the flow function marketplace. Do NOT use the other Play Audio flow funtion.

If that condition is not filled, that is to say, if the button is currently displayed as “Pause”, it will trigger “Pause audio playback”, set the page variable to “play” (for the icon to be displayed as “play” again), and finally set the visibility of the stop icon to false.

The Stop Icon

CaptureStop

Notes :

  • Create a page variable called Visibility (mine is Visibilite), set its value to True/False.
  • In the advanced properties of the icon, bind its visibility to the page variable we just created.
  • Set the 3 nodes in the logic, as shown in the above image.

3) The page logic

From the page mounted event (may be you can use the page focused event), I have :

  • Preload audio playback. You have to load the information about the audio before anything else. Set the URL to your track and give it a Audio Playback ID, which can be anything to identify your track. I put 001.
  • A set page variable form_icon to “Play”, to make sure that the icon is always play at the opening of the page.
  • Then, before the 2 loops that are going to update 2 page variables, I have a delay node set to 1 sec, which was actually crucial for me. Without it, all the logic behind would not trigger at the first opening of the page. Maybe the cause is the time required to preload the audio, or maybe the page mounted event (?)
  • Create a page variable that will receive the number in seconds about the playing track. I called it audio_info, but you could called it rather audio_current. And set the value in number.
    Find the node “Get audio playback info” in the market, and enter in the properties the ID you chose before.
    Then put a set page variable node bound to the page variable audio_info (or audio_current). The assigned value is a formula : INTEGER(outputs[“Get audio playback info”].playback.currentTime)
    The Integer formula makes the value a whole number.
    The Get audio playback info"].playback.currentTime allows you to refer to the output of that particular node directly from a formula (something a discovered along the way).
    The Delay node makes it loop every seconds, in order to constantly update the value.

The second logic loop aims to get the duration of the track in seconds.
Create a page variable called for example audio_duration, and set the value in numbers.

  • Get audio playback info
  • Set Page Variable with a formula : INTEGER(outputs[“Get audio playback info”].playback.duration)
  • A delay node

4) A forward and backward icons
I wanted them to move the audio track 15 seconds backwards or forwards
The backward logic : you need to get the node “Seek audio playback to” in the marketplace.
Link it to the component tap event. Put the audio ID and in the value set this formula :
SUBTRACT(pageVars.Audio_info, 15)
For the forward icon, it is the same and the formula an be ADD(pageVars.Audio_info, 15)

5) The Slider

Properties : bound the value to the variable audio_info.
Bound the maximum value to the variable audio_duration
Put 1 in the Step value

The slider Logic :

So you have 2 events. One is when you tap the bar of the slider, the other is when you move the button and slide it to the sides.
I put the same logic to cover both finger actions.

  • A “Seek audio playback to”, put the audio ID in the properties and set the value to “Components properties”, then “Selected component properties or output value”, and select the value in number.
  • A delay node set to 20ms. Why? I feel that without it the slider is choppy and bugging, as the page variable gets simultaneously update from the playing track and from the slider. That way there are no interferences and the value gets updated slightly after by the slider. I may be mistaken but I feel it make it more reactive. It works perfectly when the track had to time to fully load itself.
  • Get Audio Playback Info
  • Set Page Variable, with a formula : (outputs[“Get audio playback info”].playback.currentTime)
    (Be careful if you erase the previous node you will have to enter the formula again for it to work).

6) Displaying track’s current time and duration

The 0:01 on the left will display the current seconds of the track as it is playing. It is a paragraph which content is bound to this formula:
FLOOR(pageVars.Audio_info / 60) + “:” + LEFT_PAD(STRING(FLOOR(pageVars.Audio_info % 60)), 2, “0”)

And for the paragraph on the right, display the duration of the track, the formula is similar :
FLOOR(pageVars.Audio_duration / 60) + “:” + LEFT_PAD(STRING(FLOOR(pageVars.Audio_duration % 60)), 2, “0”)

I found it the forum by a post made by Mevi. It convert the seconds value from the get audio info node and put into the format minutes : seconds

And that’s it.

You might consider set a “delete audio playback” flow function when you leave the page to make some space.

Hope that’s useful!
:dizzy:

11 Likes

Thank you for creating this. Can you confirm this has been tested on the AppGyver iOS Preview app and works as intended?

Hi !
You’re welcome.
No, I haven’t tested it on IOS, but on Android and web preview.
I don’t aim to garantee things but to help the community by sharing how I did :wink:

Thank you for you extensive walk through.

I have tried numerous, and more simpler methods to play a remote audio stream.

Every method I tried worked via the AppGyver Android app and via web browser. However not one single method worked on the AppGyver iOS app.

If you look at my profile, I’ve posted and replied to others who face the same issue. I also posted a bug on the AG forum, but not a single response from any of the AG devs on a possible solution. Very frustrating.

When I get the time, I’ll try your method and see if it works.

1 Like

Link to bug. Raised 21 June.

Link to my post in forum.

@Colin_D
I have been experimenting with the set up of @Georges_Rust on iOS and it seems to work for me to play the audio! I guess they might have repaired the bug? For me crucial was to preload the audio playback - else nothing worked at all.

But I have some issues in general. Mounting the whole logic as shown below did not work for me. Instead I activated the flow function when tapping the play button and that made the magic.

Next the formular you give to show the time left to play a song did not make sense to me because the “Get audio playback info.playback.duration” is representing a fixed number of how long the song in total is. So I had to add a piece to make it count downwards:

FLOOR(pageVars.audioDuration / 60 - pageVars.audioCurrent / 60) + “:” + LEFT_PAD(STRING(FLOOR(pageVars.audioDuration % 60 -pageVars.audioCurrent % 60)), 2, “0”)

I substract the current time from the duration and it gives out the time left.

Now one more thing that didn’t work was the slider logic below:

You are showing below that you make a seek audio flow seperatly from the rest and put a 20 ms delay. That didn’t work for me in iOS. I just removed the delay and set: Component tap → seek audio playback to → Get audio playback info → Set page variable

and now its working fine!

Man I am so grateful that you wrote the whole thing down for us. It saved my day and 100% hours of head ache. Good job!

Lissuin

1 Like

Hi @Lissuin are those your flow images or are they just copies of @Georges_Rust. You seem to reference different images in your description. Can you post those? Are you saying that you have all of the logic that is in your first image in your Component tap flow?
Thank you,
Gary

Yes, sorry these are just copies of @Georges_Rust.
Here are mine:


Yes I put everything on the first flow function picture on the play button.
Hope that helps.

Lissuin

1 Like

Many thanks for this helpful tutorial!

My play/pause button seems to be stuck on “pause” once the audio has finished playing. Any tips on switching the pause icon back to a play icon once the audio finishes, and then setting the “current time” and slider back to 0:00?

Also, a “loop/repeat” button would be a cool addition, but I have no idea how to do this. Any help is greatly appreciated!

Thanks again for the awesome tutorial!

1 Like

@Georges_Rust
I have same problems as @kuharisha
And also I view as very long to preload my music files form Firebase storage like logic of this Tutorial.
Maybe you know how I can to short time of preload music files to open in my app?

Best regards for your Tutorial!!!

1 Like

Hello there,

Regarding the fact that the play button is stuck after the audio finished playing:

I may have a solution, but haven’t really tried.

The node “preload audio for playback” can give you various values as an output. I have found that one of them is the Status of the track, that can be “paused”, “ongoing” or “stopped”. I suppose that “stopped” can be useful for this issue.

After the node “preload audio for playback”, you could run a loop to check the status of the track.
Set a IF node with this formula for instance: IS_EQUAL(outputs[“Preload audio for playback”].playback.status, “stopped”)
If the status of the track is stopped, you can then run a node “set page variable” to change the icon to pause.
Then put a delay node to make a loop that will run when the audio is preloaded.

Again I haven’t tried it for myself, I hope that the “stopped” status would fire when the audio finished playing. If not, someone of the team could tell us.

Regarding you other issue:
I preload audios from Firebase storage and it is super fast. I preload like 4 audios in a few seconds, but I still have to try with lower internet conditions.

There is no way to preload music faster.
You can only try upload an audio that is lighter (what quality of mp3 are you uploading?)
Or you can preload the audio earlier, when opening the app, or on the previous page.
You can even create a button that the user can press to preload all the tracks of the app, to be used later.

Thank you, @Geoges_Rust!

Maybe you can write how I can preload all files click by one button and don’t slow my app or break out?

Thanks a lot,
Yaroslav

If you want to preload the files as soon as the app is launched, you can link the node “app launched” in the global canvas to the node “preload audios”.

In the same way, you can add a button in your app and in the logic link the node “preload audio”. You can preload various audios at the same time. Just put various nodes and in the parameters of each node you add a different link and a different ID for each track. Each one track will then be available to play later in the app. When you play it, just enter the right ID.

It doesn’t make the app crash as far as I know.

Hello, @Georges_Rust

I tested this method to change icon of button pause to play as slider back to 0:00, but playback.status is always as stopped, and not change button as music the end, but change button always to play. Please check it.

Thank you! That’s right, and it seems logical, but I have a few practical questions:

  1. I have about 100 songs in my firebase storage, and they may be supplemented in the future
  2. I use a node “Firebase storage get download URL” to extract each song every time and use it every time with “Preload audio for playback” with id number 001
  3. How can I find out the link without a node “Firebase storage get download URL” and pull everything if now there are 100 songs and tomorrow I will upload another 20 will be 120 - how to transfer additional songs to the application, find out their download links - do you have such a solution as you describe?

Снимок экрана 2022-09-27 в 14.43.56

Hi

I did not even know that the node “Firebase storage get download URL” existed.

To get the link of your files uploaded to Firebase storage, go to the file, click on it, on the right panel that opens under “name”, click on it, your file opens in a browser tab, copy the URL.

(Sorry for the 1st issue concerning the fact that the track doesn’t go to zero after playing, but unfortunately I won’t have time to dig into it right now)

@Georges_Rust @Mevi Attention please!
I have some bugs in this flow functions:
I find it on iOS devices.

  1. If I switch between open applications music is close - How I can to do music continue play when app is switch for basic screen of my device.
  2. If I switch between open applications and return to my AppGyver app, music is continue play, but slider and timer is not work and I can’t to reset timer and slider neither button stop nor play/pause button. Please check this bug and give solution ASAP.
  3. Please give answer how I can to preload many files from Firebase storage in App launcher.