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
Posted in General | Leave a comment

Use power of database to speedup your application!

Learn with fun

In this blog post, I am going to tell you some queries/ tricks to speed up your application by using the power of database. I am using postgres and activerecord rails so all queries are related to these, but you can relate it with your database.

Recently I got some performance issue when our user base increased many folds. We did some optmization and would like to share the tips:

Note: As I am using ActiveRecord most of the examples have ActiveRecord syntax with corresponding SQL statement

Select only required fields from database – Not all

Mostly developers miss to specify the required columns and instead select all fields from database which leads to performance degradation.

Let us say my User Table has 100 users

Above query took 15.4 ms as it is selecting all columns from the table. But, the query below took only 3.3ms.

Here we are not…

View original post 744 more words

Posted in General | Leave a comment

How to upload a large CSV efficiently using rails!

Think, Click and Succeed

Active-record is an abstraction layer that facilitates creation, deletion and use of ORM objects whose data requires persistent storage to a database. This keeps us away from having to think too much about SQL level queries and makes it very easy for us to work with data. It gives us super easy interface that helps us to do “almost” anything that we can do with bare SQL statements. Apart from the basic CRUD operations, active-record lets us do more complicated database stuff like pick a group of records based on a criteria, order them, join tables, perform mathematical operations, etc.

Active-record pattern is liked by most because of the above mentioned reasons. But using active-record solely may not help when your application scales.

For example, active-record does not have a support to bulk insert into the database. Ofcourse we can use gems to do that, but I personally…

View original post 661 more words

Posted in General | Leave a comment

Loading…widgets in react-redux application

I got an interesting requirement for my React app to display multiple widgets with the following conditions:

  1. Number of widgets to displayed – UNKNOWN
  2. Content to be displayed – UNKNOWN
  3. API endpoints – UNKNOWN
  4. Only known thing was the placeholder in the widgets where data needs to be displayed
  5. Need to display loader for each API call

Fortunately, an API was available to get details such as the number of widgets and their endpoints.

As per the requirement to display loader for each API call, the first screen was:

main-widget Initial Loader screen

When the first API returns the response containing details regarding widgets such as the number of widgets and their endpoints, the above widget should turn into the following screen if there are 4 widgets data returned by initial API call:

widget-loaders
screen 2

And each of the widgets will call different APIs to get the data it needs…

View original post 524 more words

Posted in General | Leave a comment

Choosing testing framework for your React application

Let's make learning fun!

Recently, while working on a React/Redux based single page application, I was required to choose a testing framework. Since this was my first attempt at testing JavaScript based front-end applications, I started googling around to find the best possible tool to automate testing of my application. It was not long before I ended up being totally confused. Do you know why?

Because there are too many to choose from and it’s tough to decide, since they all do basically the same thing:

  1. Describe what you’re testing
  2. Set up what you’re going to test
  3. Assert whether the thing did what you expect

Having said that, when you have to choose, no matter how hard it is, you have to choose.

Test tools can be divided based on functionalities that they provide. Some provide us with only one functionality, and some provide us with a combination. It’s common to use a combination of…

View original post 755 more words

Posted in General | Leave a comment

AWS EC2: Increase volume size on the fly

The AWS documentation is pretty detailed and thorough, but sometime I feel it is overwhelming and at times some important steps/command are deep down somewhere, essentially very hard to find or perhaps missing!! I had a similar experience recently.

I hit upon a low disk warning for the root volume of a production instance. I was nervous, but thankfully AWS EC2 supports on the fly increase of volume size (for the kernel that supports on-line resizing, ofcourse). The other option is obviously to create a new instance with larger volume & switch. Not necessary though!!

The first step was to look for documentation and confirm if my instance type supports it. The very first link Google returned was what I was looking for. My Instances are running Ubuntu (mainly 16.04.2 LTS) and AWS does support on the fly volume changes for this. Hurrah!!

The steps in the AWS documentation are certainly detailed but elongated and scattered. It can take a couple of hours to go through and understand the actual set of steps. Additionally, some commands are missing. Let me put down the exact steps and save some trouble 🙂

  1. Increase the volume size: This can be done using “command line” or the “console“. I prefer the console. The steps on the console link are concise.
  2. Monitor the progress: In the AWS documentation go to the section “To monitor progress of a modification from the console”. Once the state is shown as “completed (100%)” proceed to step #3 below. Tip: I increased size from 30GB to 100GB.
  3. Extend the volume’s file system: To take advantage of the increased storage capacity.
    • Check the existing disk configuration by using the command ‘lsblk’. It will show something like below:
      xvda 202:0 0 100G 0 disk
       └─xvda1 202:1 0 30G 0 part /

      This denotes that disk size is 100 GB and allocated to xvda1 is 30GB. Usable is only 30GB, which is on the partition xvda1.

    • Now grow the xvda1 partition to the maximum available disk size. Important: Ensure to use the correct partition. Read ‘growpart’ command documentation, if need be.
      sudo growpart /dev/xvda 1

      you will see a message like below:

      CHANGED: partition=1 start=16065 old: size=62898462 end=62914527 new: size=209699102,end=209715167

      NOTE: The growpart command is missing from the AWS documentation on Extending a Linux File System after Resizing the Volume.

    • Verify that the allocation has changed using the ‘lsblk’ command again. It should now show the entire 100GB allocated to xvda1, as shown below. Tip: At this point the usable space is still ONLY 30GB though it shows 100GB.
      xvda 202:0 0 100G 0 disk
      
      └─xvda1 202:1 0 100G 0 part /
    • Finally tell the OS to use the additional space by resizing the partition.
      sudo resize2fs /dev/xvda1

      you will see a message like below:

      resize2fs 1.42.13 (17-May-2015)
      
      Filesystem at /dev/xvda1 is mounted on /; on-line resizing required
      
      old_desc_blocks = 2, new_desc_blocks = 7
      
      The filesystem on /dev/xvda1 is now 26212387 (4k) blocks long.
    • You will see 100GB allocated to your partition. Verify using ‘df’ command!!
  4. Done. Your volume is now having the increased size!!

IMPORTANT: It is not mandatory, but as a fail safe mechanism, always take an image of the instance that you intend to modify.

NOTE: The option to support on the fly increase in volume size is specific to OS (kernel should support on-line resizing). And, for EC2 the steps could vary as per instance type. However, using the steps above, I have successfully increased the volume size of both m4.xlarge and m4.large instances running ubuntu 16.04.2 LTS.

Posted in General | Leave a comment

Getting started with Android and Kotlin

Android Experience

With Google IO 2017, Google announced Kotlin as the officially supported language for Android.

Kotlin will be now shipped with Android Studio working out of the box, starting with version 3.0. No extra installations needed. No more incompatible plugins. All thanks to close collaboration between JetBrains and Google.

Why Kotlin?

Most importantly, it was because we think Kotlin is a great language that will make writing Android apps easier and more enjoyable.

Kotlin is also a great match for the existing Android ecosystem. It is 100% compatible with the Java programming language. We can add as little or as much Kotlin into our existing codebase as we want and mix the two languages freely within the same project.

A Quick Tour

here is a quick tour of some of the particularly appealing aspects of Kotlin:

1.Null Safety

One of the Kotlin’s best features is null safety. The Kotlin compiler enforces…

View original post 558 more words

Posted in General | Leave a comment