Home > database >  How to conditionally play an audio clip in R Shiny?
How to conditionally play an audio clip in R Shiny?

Time:03-17

Goal

Play an audio clip for navigation whenever the reactive value of position is in a certain range

What I tried

Based on other questions, I found that a button can be used to play an audio clip. For example:

An example with action button

library(shiny)

addResourcePath("Music", "Music")
audio_file1 <- "Music/in 200 m turn left.mp3"



ui <- fluidPage(
  
  basicPage(
    actionButton("play", "Play the Audio")
  )
  
)



server <- function(input, output, session) {
  
  observeEvent(input$play, {
    insertUI(selector = "#play",
             where = "afterEnd",
             ui = tags$audio(src = audio_file1, type = "audio/mp3", autoplay = NA, controls = NA, style="display:none;")  
    )
  })
}


shinyApp(ui, server)

My modifications without an action button

I want to autoplay the audio clip whenever the position x is a certain value. For keeping the question short, I am providing x inside server in this example:

server <- function(input, output, session) {
  
  x <- 1
  
  observeEvent(if (x==1){return(x)}, {
    insertUI(selector = "#play",
             where = "afterEnd",
             ui = tags$audio(src = audio_file1, type = "audio/mp3", autoplay = TRUE, controls = NA, style="display:none;")  
    )
  })
}

However, that threw an error:

Warning: Error in eval_tidy: no function to return from, jumping to top level
  [No stack trace available]  

I have also separately tried using the uiOutput and renderUI as follows (server part):

  output$audioo <- renderUI({
    
    if (x > 0.5 & x < 1.5) {
    
    tags$audio(src = audio_file_200_TL, type = "audio/mp3", autoplay = TRUE, controls = NA)  
      
    } else {
      
      tags$h1("My header")
    }
  
    
    })

But that plays the audio when the app is just launched and the audio does not play when x is in the provided range. How can I conditionally play an audio clip without using an action button?

CodePudding user response:

So x is not an input nor a reactive. We need this as R process has to know the time to rerun the cycle. There are other hardcore solution which I am not recommending like shiny::invalidateLater().

Try sth like:

x_r <- reactive(x)

observeEvent(x_r(), {
 if (x_r() == 1) {
    insertUI(selector = "#play",
             where = "afterEnd",
             ui = tags$audio(src = audio_file1, type = "audio/mp3", autoplay = TRUE, controls = NA, style="display:none;"), immediate = TRUE 
    )
 }
})

Btw be very careful with insertUI, I do not like to use it as we might add the same element many times. More elegant strategy for me is to add the element by default and later only edit in the DOM, hide/show/edit. we could use shinyjs package for such action. insertUI often need immediate = TRUE argument.

EDIT:

This app is working perfectly for me. The question is what is the x in your app. mp3 taken from https://samplelib.com/sample-mp3.html.

library(shiny)

addResourcePath("Music", "Music")
audio_file1 <- "Music/sample-3s.mp3"

ui <- fluidPage(

  basicPage(
    tags$div(id = "AUDIO_MY"),
    selectInput("STH", "STH", 1:10, 1)
  )

)



server <- function(input, output, session) {
  observeEvent(req(input$STH == "1"), {
    insertUI(selector = "#AUDIO_MY",
             where = "afterEnd",
             ui = tags$audio(src = audio_file1, type = "audio/mp3", autoplay = NA, controls = NA, style="display:none;")
    , immediate = TRUE)
  })
}
  • Related