Research
Security News
Threat Actor Exposes Playbook for Exploiting npm to Build Blockchain-Powered Botnets
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
audiolooper
Advanced tools
An AudioLooper let's you loop your audiotracks (Audio-objects) in a very simple and intuitive way. The looping algorithm keeps the tracks in sync. The algorithm is executed in a separate thread(a Web Worker) because of the enhanced performance that it delivers (so the performance is not dependent on the complexity/current state of the UI), which is the most important thing to have for an exact timing.
The looping algorithm keeps all tracks in sync according to the first added track. It just works with the durations and ids with the tracks you add, so no information about the actual Audio-object is needed.
The first track you add is the most important one: Based on the duration of it, tracks will be synced and played.
First of all, when the first track gets added, it just gets looped over and over as is. Since the algorithm works with percentual durations, the first track gets assigned a maximal percentual duration of 1. So from now on, this track is the unit used for all the new tracks added. I know, that doesn't sound very clear until now, but wait for it, it soon will! :sparkles:
Now, if new tracks get added, the magic happens. When you add a new track, one very important constant gets calculated: The percentual duration of the track according the the first one. So the duration of the first track will be 100%. E.g. if the duration of the first track is 1s and the duration of the new track is 1.2s, the new track will have a percentual duration of 120%. This information will later on be used to determine whether a track needs to be played or not.
So now, as a new track was added, the looper will include that one and loop it. But how does the looper decide if a track needs to be played or not? That's the heart of the looper, the most important question. Although it's a small piece of code, it was the most complicated part where I also spent most of the time. It works as follows: The looper always calculates the actual progress of the first track. This progress is expressed percentually. Now, the looper looks at the percentual duration of every added track and determines, if the track can be played now. Here, the looper rounds the percentual duration of the current track to the next bigger integer(e.g. 1.4 becomes 2). Now, if the following condition evaluates to true, the track is played.
(firtTrack.percentualProgress % ceil(currentTrack.percentualDuration)) == 0
But what does this mean? This means that the tracks are always played in sync with the first track: If a track's duration is shorter or equal than the first track's duration, it's always played when the first track is played (which, how I said before, always gets looped as is). If a track's duration is greater than the first track's duration, it's always looped in a way so that this track doesn't overlap itself: If it's 2x as long as the first track, it get's played always after the first track has played 2 times. The same would apply to a percentual duration of 1.2, 1.1, 1.999, ... you name it. Also, e.g. if the track is 3x as long as the first track, it's played every third time the first track is played. I think you get it. It's quite a complicated method but I think that it's a reasonble and logic one to automatically sync tracks.
To clarify everything a bit, here's a graphic which explains the method with an example:
In the image we can see a table where the tracks are listed together with some information: The track-nr to identify the tracks, the duration and when they will be added.
In the second table (the blue one) you can see when the specific tracks are played. If there's a green arrow, it means that this track is played. The black lines with the circle show when the track was added.
The looping algorithm is executed in a Web Worker. Web Workers can't interact with the DOM APIs, so passing all tracks as direct references to the Audio-object is technically not possible. Therefore, you just pass an id (to identify the tracks) and the duration of the track. The algorithm then just works with these 'virtual' tracks. When a track is played/stopped by the alogrithm, your callbacks get executed. To enhance accuracy, you can call a function which continuously syncs the real track (so the audio-object in your UI-thread) with the virtual track in the other thread. This (as far as I was able to test it) increases accuracy up to over 90%. Still, sometimes there are delays (as far as I was able to test it, the delays had a length of ~2-10ms, so they weren't noticeable).
new AudioLooper(onPlay, onStop)
You can construct a new AudioLooper object with this constructor. The arguments are:
This function gets exectued everytime a track needs to be played (according to the algorithm). The function takes 1 argument: The id of the track (you determined it before when you added the track to the looper). In the body of this function you can react accordingly to the play action: Here you would play your 'real' tracks, so the audio-objects you created (which can be identified by an id, which was also determined by you).
This function is comparable to the onPlay - callback. The function takes 1 argument: The id of the track. The only difference is that this function gets called when a track needs to be stopped.
.addTrack( { id, duration } )
This method adds a track to the looper, so it can be processed by the algorithm. NOTE: This method adds the track to the looper, but you need to store your (real) tracks on your own. This has 2 reasons:
It takes on argument, an object with two properties:
.removeTrack( { id } )
This methods removes the track from the looper: So it won't be processed again by the looper. NOTE: It doesn't remove your real track, so you have to remove it by yourself and let the garbage collector do the rest.
It takes one argument, an object with one property:
.play( { id } )
This method plays a track again if you have stopped it before. NOTE: Per default, a track is played after it's added.
It takes one argument, an object with one property:
.stop( { id } )
This method prevents a track to be looped again. NOTE: This doesn't mean that if a track is currently playing, that it will be stopped. That's something you have to do on your own.
It takes one argument, an object with one property:
If you don't need the looper anymore, you should consider disposing it, otherwise the thread will keep running in the background. To do so, just call:
.dispose()
That's the more complicated part of this module, it may take some time to understand. But hey: This literally rocks the timing! :musical_note: :fire:
.syncFirstTrack(audioObject)
One big problem I encountered during the testing of this module was, unsurprisingly, the timing. There have been latencies up to 300ms. And this problem had two main reasons:
I fixed this problem by stringifying the message objects I passed between the two threads to JSON and parsing that string at the recipient side. I gained quite a better performance than before, but it was still not acceptable.
I hope that now it's clear when and how to use this method. NOTE: Only call this mehod once!
FAQs
AudioLooper - Loop your tracks with automatic synchronization.
The npm package audiolooper receives a total of 0 weekly downloads. As such, audiolooper popularity was classified as not popular.
We found that audiolooper demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
A threat actor's playbook for exploiting the npm ecosystem was exposed on the dark web, detailing how to build a blockchain-powered botnet.
Security News
NVD’s backlog surpasses 20,000 CVEs as analysis slows and NIST announces new system updates to address ongoing delays.
Security News
Research
A malicious npm package disguised as a WhatsApp client is exploiting authentication flows with a remote kill switch to exfiltrate data and destroy files.