Audio recorder using javascript works, but how to get the recorded content into a media object?

I use a custom html and javascript to record audio from my microphone. This part works fine (see example below). But now I want the recorded audio to be stored in a data table. It lives in a javascript variable (‘blob’), but how can the content of this be collected and stored from the python side?

Yes, Anvil can exchange variables between javascript and python, but as far as I know this only applies to things that can be stored in a JSON object. Perhaps it is possible to convert/transfer the (binary?) audio as a string and convert it back again on the python side?

Here is the app with the recorder (and playback):
https://anvil.works/build#clone:XNWKXWJ4YTKWORYP=6V6MK7FFK43OZKMGJOMYCRVJ

1 Like

Hi @hans.melberg
here’s an approach.
https://anvil.works/build#clone:VPMKXDIAKDPEGRGY=ONMRE3XORAHRQQNCUOHYIVQQ
Audio recorder custom form has been configured as custom component, so it can raise events and has a property “audio”.
Then in the javascript I set the hooks for getting the audio binary when “stop” is clicked.
Actually anvil can pass to python code also the Javascript’s native blob object, the problem is anvil doesn’t know how to manage it (or at least I don’t know how to do that in Anvil).
So the trick is - as you pointed - base64 encode the audio binary and send the string to Anvil code, then convert back to binary in a media object.
Curiously, the base64 conversion code doesn’t work in client code so I had to code a server function for that.
In the end: not a coding masterpiece but a starting point illustrating a working way.
Hope this helps.
BR

5 Likes

Fantastic! I suspected that some javascript genious could come up with a solution. Thank you!

1 Like

Maybe it is just me, but it seems like the recorded audio objects in the data table are all empty? There is a name and an object, but nothing inside?

After debugging javascript, I am beginnng to love Python even more!

Two-three strange things happened, at least one of which I solved:

  • First, the saved files were empty. The problem, I think, is that there should not (?) be a space in the following line in the javascript added to the AudioRecorder:
    base64_audio_string = base64String.substr(base64String.indexOf(', ') + 1); 
  • However, there were still problems, so I tried a debug and followed the execution line by line
  • This worked in Firefox - and the audio file was stored in the data table. Hurrah!
  • But strangely it did not work when the debug mode was turned off. And it did not work in Chrome (even in debugger mode)
  • All of which makes me suspect that there is some synchronization issues, that the code races ahead with some stuff without having finished some other tasks?
    But I am at the limit of my javascript competence here. Anyone?

The current code is here:

https://anvil.works/build#clone:YPYB5R7ZMPFQ7DFV=RI3JUTYOMUB7JZ62GAFK6NIW

Hi @hans.melberg
I’m surely no Javascript genius and I just proved it with my previuos post.

  1. you’re right the substring search must be done for ',' and not for ', '.
  2. the problems you were facing were due to how I declared the event handler:
reader.onloadended = notifyAnvil(reader, audio_blob.type);

This whay the notifyAnvil function is called immediately and its result assigned to onloadended.
This is not what we want.
We need to declare the handler this way:

reader.onload = function(e) {
      console.log(e);
      let base64String = reader.result; 
      console.log('Base64 String - ', base64String); 
      base64_audio_string = base64String.substr(base64String.indexOf(',') + 1);  
      anvil.call(calling_form, 'onStop', base64_audio_string, audio_blob.type);      
    };

This way the function is executed when the load ends successfully (yes, I also changed the event handler from .onloadended to .onload after having a look here).
Now it seems to work both in Firefox and Chrome and saves non-zero .objs in the database.
Of course, you can remove all those console.log and comments when everything’s working.
Bye
https://anvil.works/build#clone:36B5EBIQ3HMY3LSO=AP6LPH4VIB4P5GCSTIIA3BNN

1 Like

Or, might be cleaner and more aligned to the v1 suggestion:

reader.onload = function(e) {
      console.log(e);
      notifyAnvil(reader, audio_blob.type);  
    };

But I haven’t tried this, I’m just writing my mind out.
BR