Way to stop any previously playing sounds (base64) in javascript before playing next sound

Viewed 221

I have a javascript function that plays a particular sound from base64 plain text. What I am looking for I think is quite simple, but I am not at all familiar with js, as I'm actually using js in R as part of a shiny app. I am simply looking for a way that when this function is called, it will cancel any previously playing sound from the same or a similar function that might already be playing:

shinyjs.soundmaker = function() {
  var snd = new Audio("data:audio/wav;base64,blablablabla");
  snd.play();
}

Any help would be great!

3 Answers

The solution to this problem using js and R Shiny is to create a separate js function that stops sounds from playing. Then, each time you want to start a new sound, you first also call the sound stopping function - hence, any previously playing sound will be stopped before the new one begins.

library(shiny)
library(shinyjs)

ui <- fluidPage(

    useShinyjs(),
    
    extendShinyjs(script = "marbles.js", functions = c("marbles")),
    extendShinyjs(script = "birds.js", functions = c("birds")),
    extendShinyjs(script = "stopper.js", functions = c("stopper")),
    
    column(10, offset = 1,
           align = "center",
           fluidRow(column(4,
                           align = "center",
                           column(10,
                                  align = "center",
                                  offset = 1,
                                  br(),
                                  actionButton('sound1','Sound 1', width = '100%',
                                               style="color: #ffffff; background-color: #35467b; border-color: #2e1911"))),
                    column(4,
                           align = "center",
                           column(10,
                                  align = "center",
                                  offset = 1,
                                  br(),
                                  actionButton('sound2','Sound 2', width = '100%',
                                               style="color: #ffffff; background-color: #1dbd6b; border-color: #1dbd6b"))),
                    column(4,
                           align = "center",
                           column(10,
                                  align = "center",
                                  offset = 1,
                                  br(),
                                  actionButton('stopper','Stop sounds', width = '100%',
                                               style="color: #ffffff; background-color: #b73838; border-color: #b73838")))
           )),
)

server <- function(input, output) {

    observeEvent(input$sound1, {
        
        js$stopper()
        js$birds()
        
    })
    
    observeEvent(input$sound2, {
        
        js$stopper()
        js$marbles()
        
    })
    
    observeEvent(input$stopper, {
        
        js$stopper()
        
    })
    
    
}

# Run the application 
shinyApp(ui = ui, server = server)

The sound stopping function is simple:

shinyjs.stopper = function() {
  
  snd.pause();
  
}

Then the two sound functions would be the following, but you insert your own base64 plain text in the 'new audio' part (to convert a wav to base64, see e.g.: https://base64.guru/converter/encode/audio/wav). All the javascript functions should be saved as js files in a folder named 'www' in the same working directory as your app:

shinyjs.birds = function() {
  snd = new Audio("data:audio/wav;base64,blablablabla");
  snd.play();
}

shinyjs.marbles = function() {
  snd = new Audio("data:audio/wav;base64,blablablabla");
  snd.play();
}

In short, for whatever reason, it doesn't seem to work to just call sound.pause() at the start of the function where you make a new sound start playing. Instead, make a separate function that stops the sound, and then run the new sound afterwards.

I have been working on {howler} (currently only available on GitHub), a wrapper for the howler.js audio library. It can deal with base64 sounds, and stop sounds from playing server side with stopHowl.

Here is an example; on clicking the play button, the sound will play for 0.5s before stopping again:

library(shiny)
library(howler)

ui <- fluidPage(
  title = "howler Base64 Example",
  useHowlerJS(),

  h3("howler Base64 Example"),
  howlerPlayer("sound", "data:audio/wav;base64,blablablabla"),
  howlerPlayButton("sound")
)

server <- function(input, output, session) {
  observeEvent(input$sound_play, {
    playHowl(session, "sound")
    Sys.sleep(0.5)
    stopHowl(session, "sound")
  })
}

shinyApp(ui, server)

"Specific js code" The point of stackoverflow isn't for other people to write code for you; that way you don't learn anything. It's to point you in the right direction. But ooook

// Store your Audio in some higher scope: outside of the function
var snd = new Audio();

shinyjs.soundmaker = function() {
  // call snd.stop(); and reassign snd every time you want to play audio
  snd.stop();
  snd = new Audio("data:audio/wav;base64,blablablabla");
  snd.play();
}

Read this for more info on how scopes work

Related