Richienb / audic

Play some audio.
MIT License
68 stars 9 forks source link

Add `ended` event #8

Closed SirFireball3521 closed 2 years ago

SirFireball3521 commented 3 years ago

Describe the solution you'd like Add the ability to have a callback when a song ends. Something like:

let mysong = new Audic('file.mp3)
mysong.play(()=>{
   //code here
})

or

mysong.callback=()=>{
   //code here
}
mysong.play()

This would be useful for something like a song queue.

Describe alternatives you've considered I could use setTimeout() with the duration of the file, but that won't account for pausing and resuming.

Richienb commented 3 years ago

The Web Audio API exposes an EventEmitter with the ended event:

audioElement.addEventListener("ended", () => {
    // ...
}, false)

PR welcome for adding this.

SirFireball3521 commented 3 years ago

This is running in terminal, not browser. Unless there's something obvious that I'm missing, I don't think there is an audio element

Richienb commented 3 years ago

The Web Audio API is a best practice we should be following when doing something similar for Node.js.

SirFireball3521 commented 3 years ago

So yeah, I'm missing something obvious. I'm somewhat new to this so if you don't mind me asking, what would the name of the audio element used by Audic be?

Richienb commented 3 years ago

Audic is a class that you initialise with new Audic(path). The class needs to extend EventEmitter and broadcast an event when it detects that the song has finished playing.

SirFireball3521 commented 3 years ago

Alright, I'm really not sure how I go about that. Do I do something like this?

class Audic0 extends Audic extends EventEmitter
Richienb commented 3 years ago

The class is created like this:

class Audic extends EventEmitter

You'll then need to get the duration and time which then needs to be used to determine when the audio has ended.

SirFireball3521 commented 3 years ago

Ah okay I understand what you mean now. I apparently blanked on "PR welcome" and thought this was just for my code. Alright, when I have some time I might submit something.

SirFireball3521 commented 3 years ago

Nevermind. I can tell what the stuff here is doing, but everything in vlc is beyond me and I don't have the capability to sort it out now. It's theoretically possible I come back to this in the future, but at the moment I'm not going to do anything.

Richienb commented 3 years ago

Reopening so it can be tackled by someone else.

ajithgopi commented 3 years ago

@SirFireball3521 Use this javascript file temporarily https://github.com/ajithgopi/audic/blob/master/source/index.js

GitHub
ajithgopi/audic
Play some audio. Contribute to ajithgopi/audic development by creating an account on GitHub.
ajithgopi commented 3 years ago

I have found problems while setting the src with the src setter. When the src is set and play() is called immediately, the playback wont start because the async operation would be happening in background.

Richienb commented 3 years ago

Maybe we can assign the async function we create in set src() to this._setup like this: Promise.all(this._setup, ...). This means that the setting task will always complete before it is possible to play the content.

ajithgopi commented 3 years ago

It's still not possible to await the combined Promise in a setter function. The alternative solution would be to remove the setter and await the operations in the calling function.

But that would break existing codes if they update packages

Richienb commented 3 years ago

It's still not possible to await the combined Promise in a setter function

We can await the Promise in the async closure that is created within the setter function

But that would break existing codes if they update packages

We can create a major release if we make a breaking change.

ajithgopi commented 3 years ago

I have made some changes in my fork on commit 85aa0660ccb10652fa289447b0607847f102b060. I have also replaced the above syntax and made the callback a property which should now be used like

player.onComplete = function(){
  console.log("Completed")
}

Settings the src should now be like:

async function playSong(){
  await player.setSrc("F:\\Sample.wav")
  player.play()
}

My objective was to play random other song when the current one ends... It's working perfectly right now.

ajithgopi commented 3 years ago

I think it would be better if you pluck only the required codes from the commit and add manually. The old setter can be retained as is (it's not working anyways) so there wont be errors.