1

I would like to play an audio file in Shiny. More specifically, I would like to be able to rewind and forward the audio file.

Whenever I use a file from the internet, this works fine. However, If I place the same file in the www folder, the audio is still able to play, but rewinding and forwarding does not longer work.

I expect this has to do with the Accept-Ranges HTTP header, as also explained in Setting HTML5 audio position.

And indeed, when playing from the https URL, the accept-ranges header is set to bytes:

enter image description here

Reproducible code is given below. My question; is this an issue in Shiny, or am I overlooking something? Is there a way to set the HTTP header accept-ranges for files in the www directory?

Folder structure

.
├── app.R
├── www                    
│   ├── Jazz_Trombone.ogg

app.R

library(shiny)

ui <- fluidPage(

  # Forwarding and rewinding works fine.
  #tags$audio(id='my_audio_player',src = 'https://upload.wikimedia.org/wikipedia/commons/8/87/Jazz_Trombone.ogg',type="audio/mpeg", autostart = '0', controls = TRUE)

  # Forwarding and rewinding does not work.
  tags$audio(id='my_audio_player',src = 'Jazz_Trombone.ogg',type="audio/mpeg", autostart = '0', controls = TRUE)
)

server <- function(input, output, session){

}
Florian
  • 24,425
  • 4
  • 49
  • 80

1 Answers1

4

Not sure if you're running shiny-server or not... so i'm going to provide a solution that doesn't include editing anny configuration files. This worked on both local(win7x64) and linux(ubuntu)...

All I really did was base64 encode the file, and pass that to the html-tag.

app.audio <- function(url = NULL, ...){
  https_url <- 
    'https://upload.wikimedia.org/wikipedia/commons/8/87/Jazz_Trombone.ogg'
  local_path <- "inst/www/Jazz_Trombone.ogg"
  as_b64 <- markdown:::.b64EncodeFile(local_path)

  ui <- fluidPage(
    column(4, tags$h4('https via url'),
           tags$audio(
             controls = "controls",
             tags$source(
               src = https_url,
               type='audio/ogg; codecs=vorbis')
           )),
    column(4, tags$h4('via local_path'),
           tags$audio(
             controls = "controls",
             tags$source(
               src = local_path,
               type='audio/ogg; codecs=vorbis')
           )),
    column(4, tags$h4("via base 64 encoding"),
           tags$audio(
             controls = "controls",
             tags$source(
               src = as_b64,
               type='audio/ogg; codecs=vorbis')
           ))
           )


  server <- function(input, output, session) {

  }

  shinyApp(ui, server)
}

Which results in:

> app.audio()

enter image description here So the local path isn't working, although check out ?shiny::addResourcePath for setting a valid global path in-app; that might work also.

Edit

Was able to get each attempt working with full functionality of controls... ran locally on windows to mimic your setup and adding the resource path seemed to fix all the issues.

app.audio <- function(url = NULL, ...){
  # Instruct shiny to add this resource path so we can call/source files from
  # the /inst/www with only www
  addResourcePath(prefix = "www", "./inst/www")
  https_url <- 
    'https://upload.wikimedia.org/wikipedia/commons/8/87/Jazz_Trombone.ogg'
  local_path <- "inst/www/Jazz_Trombone.ogg"
  as_b64 <- markdown:::.b64EncodeFile(local_path)

  ui <- fluidPage(
    column(4, tags$h4('https via url'),
           tags$audio(
             controls = "controls",
             tags$source(
               src = https_url,
               type='audio/ogg; codecs=vorbis')
           )),
    column(4, style="background:#F5F5F5", tags$h4('via local_path'),
           fluidRow(tags$h5("using htmltools::tag"),
           tags$audio(
             controls = "controls",
             tags$source(
               src = "www/Jazz_Trombone.ogg", # changing to resource-path prefix
               type='audio/ogg; codecs=vorbis')
           )),
           fluidRow(tags$h5("Using good-ole html"),
           # Testing with straight up html
           HTML(paste0(
             c('<audio controls>',
               ' <source src="www/Jazz_Trombone.ogg" type="audio/ogg; codecs=vorbis">',
               '</audio>'), 
             collapse = "\n")))),
    column(4, tags$h4("via base 64 encoding"),
           tags$audio(
             controls = "controls",
             tags$source(
               src = as_b64,
               type='audio/ogg; codecs=vorbis')
           ))
           )


  server <- function(input, output, session) {

  }

  shinyApp(ui, server)
}

enter image description here

Carl Boneri
  • 2,632
  • 1
  • 13
  • 15
  • thanks! This works perfectly. Could you please explain why base64 encoding solves the issue? – Florian Apr 03 '18 at 09:52
  • Can you tell me what system you are running? If hosting shiny-server it's a more detailed explanation as to why the local should/isn't working. But base64 encoding solves the issue because the `src` attribute isn't looking for a file-path that isn't found(this is why the local file isn't loading in the browser: Request URL: http:///www/Jazz_Trombone.ogg|Request Method: GET|Status Code: 404 Not Found. So-`base64` encoding the file itself is kind of like adding in-lined css rules...the parent tag gets its needs directly. https://en.wikipedia.org/wiki/Base64 – Carl Boneri Apr 03 '18 at 10:01
  • @Florian sorry if my explanation isn't terribly clear; it's too early and the coffee hasn't hit yet. But if it's good for use-case; maybe hit that check? – Carl Boneri Apr 03 '18 at 10:10
  • Hi @Carl, I am running Windows. However, the problem was not that the file was not found, in the case of the local path I was actually able to play the audio, only forwarding and rewinding did not work. That is why I am a bit confused that the solution works ;) – Florian Apr 03 '18 at 10:13
  • The base 64 thing did the trick for me too! It must somehow encode the file in such a way that the browser can access the `range` and `Content-Length` attribute headers of the associated object – Antoine Jan 30 '23 at 06:39