Search code examples
javascriptjavaangularjsaudioangular-resource

Sending audio data (base64) using $resource


I'm working on an app where I need to record audio using a microphone and send it to a backend app (tomcat server).

It seems that sending too big streams drives angular crazy and freezes my browser.

To record my audio file, I use the native function RecorderWorkerFactory.getUserMedia() which allow me to get a RecordBlob object.

After that, still in Angular, I extract the audio content in base64 enconding, and I send it to the backend app using $resource. The backend app correctly receives the data and process it, but the callback of this call is never executed, as Firefox detects an infinite loop and freezes.

However, if I keep running the program, after a very long time the page refresh will pass.


This is the code where I extract the audio content into base64 String, to send it:

var blob = $scope.audio.recordBlob;
if (blob) {
    var reader = new FileReader();
    reader.readAsDataURL(blob);
    reader.onloadend = function() {
        $scope.audioContent = reader.result;
        $scope.sendMessage();
    }
}

$scope.sendMessage = function(){
    var outputStream = {
                      "audio": $scope.audioContent
                     };
    $scope.sendIM(outputStream);
}

Here I send outputStream via POST to the back, and in callback I launch loadData() function that reload my view.

services.FileCreation= $resource(URI_SERVICE_CREATION, {}, {
    'post' : urlEncodedFormPost
});


$scope.sendIM = function(fluxSortie) {
  $services.FileCreation.post(angular.toJson(outputStream)).$promise.then(function(result){ 
        $scope.loadData();
    });
}

And this is the Java code for the creation of the audio file:

private void createAudioFile(File file, byte[] content) throws IOException {
    FileOutputStream stream = null;
    try {
        stream = new FileOutputStream(file.getPath());
        IOUtils.write(content, stream);
    } catch (IOException e) {
        LOGGER.debug("creation failed");
    } finally {
        if (stream != null) {
            stream.flush();
            stream.close();
        }
    }
}

Where content is the conversion of the base64 string sent.


After research I found that the infinite loop is in a native Angular function named shallowClearAndCopy() that occured after the Java execution but just before the callback. In this function the code apparently transforms each character of the audio string (base64 encoded) into an object property and do a loop on these to delete them. But this lead to a very long treatment that Firefox consider as an infinite loop.

function shallowClearAndCopy(src, dst) {
  dst = dst || {};

  angular.forEach(dst, function(value, key) { // This is where it freezes, as dst contains all my base64 encoded data and iterate over each character of it (which is veeeeeery long !)
    delete dst[key];
  });

  for (var key in src) {
    if (src.hasOwnProperty(key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
      dst[key] = src[key];
    }
  }

  return dst;
}

Is it because of angularjs performance (and there is nothing else to be done) ? Or am I missing something that creates an infinite loop ? Or is something wrong in my callback definition ?

Cheers !


Solution

  • I found, the problem!

    It was the angular.toJson(outputStream) that transformed the object without need.