Record and export Audio files in browser using Recorder.js and upload it on cloud.

Content posted here with the permission of the author, who is currently employed at Josh Software. Original post available here.

In this article, Let’s see how audio recording is possible without any shim or plugin, but only by using the Recorder.js library in the browser and how to upload recorded file on s3 (Or any other cloud storage). Before going to do audio recording first we will see which technology we need and why.

There are resources available for handing these individually but not together. I used references from below links. It is advisable to read below links before proceeding.

Technology Used:

How does the recording process works?

To record audio in the browser, you will need obviously access to the microphone with the getUserMedia API and the AudioContext API, so be sure that your browser supports these APIs

  • Web Audio API

The Web Audio API is a JavaScript API for processing and synthesizing audio in web applications.The API supports loading audio file data in multiple formats, such as WAV, MP3, AAC, OGG and others. Browser’s support for different audio format varies(Check Here).

  • AudioContext API

The AudioContext is used for creating, processing and decoding audio. You need to create an instance of AudioContext class before you can do anything because all are processed / decoded, controlled for audio generation by this API.
How AudioContext declare?:

window.AudioContext = window.AudioContext or window.webkitAudioContext
  • getUserMedia API

Before going to do recording we should know whether our web application can access user’s camera or microphone. So getUserMedia is an API that gives a web page access to a user’s camera and microphone via JavaScript. getUserMedia() has been supported since Chrome 21, Opera 18, and Firefox 17.

Make sure your application is secured with HTTPS protocol to use “getUserMedia API”. It does not work on insecure origins. Starting with Chrome 47, getUserMedia() requests are only allowed from secure origins: HTTPS or localhost.
How to check getUserMedia

if navigator.getUserMedia
  # do something cool
else
  # fallback code
  • Recorderjs

Recorderjs is a JavaScript library that records audio input (Web Audio API AudioNode object) and encodes to audio file image (Blob object). It supports three encoding formats. By using Recorder.js, the recording process is very simple. All that you need to do is to request the microphone in browser, once the user allows the access to the microphone, a stream object is received in the success callback of the initialization.This stream needs to be handled with the createMediaStreamSource method from an instance of the AudioContext API.All the variables should be stored globally or at least accessible in the scope for the rest of functions.

To understand above explanation, added code here:

startUserMedia = (stream) ->
  input = window.audio_context.createMediaStreamSource(stream)
  console.log 'Media stream created.'
  window.recorder = new Recorder(input, 'audio/mp3')
  window.recorder.record()
  console.log 'Recorder initialised.'
  return

The Recorder.js class expects the handled stream as first argument namely the input. With this instance of Recorder.js you can trigger the record method that starts to recording the received Audio and it will run indefinitely until the stop method from the same instance of recorder is triggered.

Export Recorded Audio

Export the Audio Blob from the recorder audio using the exportWAV method of the recorder instance. The exportWAV method can export the audio in wav and mp3 format when the second parameter is specified with the correct mimetype (‘audio/wav’, ‘audio/mp3’). Don’t forget to use the clear method of the recorder to start with a new one later. With the generated blob you will be able to upload it as an audio file to the server, in the same browser or just to play it in the same document.
Added Code here:

createDownloadLink = ->
  recorder and recorder.exportWAV((blob) ->
    url = URL.createObjectURL(blob)
    li = document.createElement('li')
    au = document.createElement('audio')
    hf = document.createElement('a')

    au.controls = true
    au.src = url
    hf.href = url
    hf.download = 'audio.mp3'
    hf.innerHTML = hf.download
    li.appendChild au
    li.appendChild hf
    playRecord.appendChild li

How to record Audio with Recorder.js

To make the explanation as simple as possible, we’ll just write a haml document that implements all the previously described process. It consists of 2 buttons namely Start and Play that triggers the recording process with Recorder.js. When the user stops the recording, it will append an Audio Track to an UL list with a downloadable audio file with like “audio.mp3”:

HAML code:
Create 2 buttons as “Start Recording” and “Stop Recording”

!!!
%html
  %head
    %meta{:content => "text/html; charset=utf-8", "http-equiv" => "Content-Type"}
    %title Live input record and playback
    :css
      ul {
          list-style: none;
      }

      #playRecord audio {
          display: block;
          margin-bottom: 10px;
      }
  %body
    %h1 Recorder.js export example
    %button#start-btn Start recording
    %button#stop-btn{:disabled => "disabled"} Stop recording
    %h2 Stored Recordings
    %ul#playRecord

Click on Start button will start recording and clicking on Stop button will stop recording and export it.

$('#start-btn').on 'click', ->
  if confirm "Once you start recording, you can't pause it."
    initAudioRecording()

$('#stop-btn').on 'click', ->
  stopRecording(this)

stopRecording = (button) ->
  if window.recorder != undefined
    window.recorder  window.recorder.stop()
    createRecording()
    return

createRecording = ->
  recorder and recorder.exportWAV((blob)
    data = new FormData();
    data.append("audio", blob);
    console.log(data)
    $.ajax
      url: 'Your Controller path'
      type: 'POST'
      data: data
      contentType: false
      processData: false
      success: ->
        console.log "Successfully uploaded recording."
  )
  return

startUserMedia = (stream) ->
  input = window.audio_context.createMediaStreamSource(stream)
  # console.log 'Media stream created.'
  window.recorder = new Recorder(input, 'audio/mp3')
  window.recorder.record()
  # console.log 'Recorder initialised.'
  return

initAudioRecording = ->
  try
    window.AudioContext = window.AudioContext or window.webkitAudioContext
    navigator.getUserMedia = navigator.getUserMedia or navigator.webkitGetUserMedia or navigator.mozGetUserMedia
    window.URL = window.URL or window.webkitURL
    window.audio_context = new AudioContext
    console.log 'navigator.getUserMedia ' + (if navigator.getUserMedia then 'available.' else 'not present!')
  catch e
    alert 'No web audio support in this browser!'
  navigator.getUserMedia { audio: true }, startUserMedia, (e) ->
    console.log 'No live audio input: ' + e
    return
  return

Browser Support

  • Make sure you are using a recent version of browser.
  • Make sure your application is secured with HTTPS protocol to use “Web Audio API”. It does not work on insecure origins. As of Chrome 47, the getUserMedia API cannot be called from insecure origins.
  • There is no issue while implementing Web Audio API in development environment i.e. http://localhost:3000
  • You can test your browser compatibility test.Here

How to upload recorded file on s3

Till now we have seen how to get audio blob object, but the major challenge is how to upload this audio blob on s3(or on cloud).
See below coffee script code:

createRecording = ->
  recorder and recorder.exportWAV((blob) ->
    data = new FormData();
    data.append("audio", blob);
    $.ajax
      url: 'Your controller path to upload recording'
      type: 'POST'
      data: data
      contentType: false
      processData: false
      success: ->
        if confirm "Successfully uploaded recording."
          window.location.href = 'Redirect path after successful ajax call.'

To make it very simple to understand I will explain you above code:
I have created a method as “createRecording” which calls exportWAV() method from Recorder.js, so we get a blob object.
Our aim is to upload this blob object on s3, for that I have created FormData() object and append audio blob to FormData() object.
Send this FormData() object to server by ajax call with “POST” method.

NOTE:
As we may be sending large amount of data to server (in terms of MB), we should have proper nginx entry for client_max_body_size.We should change nginx configuration in file /etc/nginx/nginx.conf, to expected max size of our recorded file.

client_max_body_size 50M;

Let’s see server side implementation:

def your_controller_method
    @model_object.audio = params[:audio]
    @model_object.save
    render nothing: true
end

Once file object reaches to your server upload same to S3 (or any other cloud storage) using regular file upload method.

For uploading file we have used carrierwave gem(click here)

Advertisements
This entry was posted in General. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s