Pyaudio client end (using microphone user)

What I’m trying to do:
Hi there,
I am working on an application for which I need the user’s audio input… I would like to use the file after recording and send it to a db.

What I’ve tried and what’s not working:

I wrote a function using pyaudio and wave, which works fine on my computer, but trying to connect it using uplink will activate the fuction on my pc and on the Anvil server this function also doesn’t make a lot of sense and doesn’t work… The only thing that would probably work if it is on the client side. However, I don’t think that is possible on Anvil, is there any comprehensive solution that can solve this? I am new at programming and Python is pretty much the only programming language I know right now.

So are you saying you have the same code in a Server module and in an Uplink file and a function with the same name is running in both?

Can you give a code snippet, that might help troubleshoot. :slight_smile:

You are limited in Python packages on the client side of things, but you have full access to Javascript and HTML 5 functions. Here’s a thread that talks about using Javascript to record audio and then transfer it to the server for further processing: Audio recorder using javascript works, but how to get the recorded content into a media object?

That might give you a starting point.

1 Like

We’ve also updated how to work with javascript in python.
And - recently we’ve added a method to help with this type of task. anvil.js.to_media()

To use client side audio/video it’s usually necessary to work with the browser api.
Trying to get a sense of what’s required from MDN examples can help.

Steps:

  1. get the media stream with navigator.mediaDevices.getUserMedia
  2. create a media recorder from the stream
  3. start the media recorder
  4. stop the media recorder
  5. use a python callback - when data (as bytes) is available append it to a list
  6. use a python callback - when you stop recording convert the data to a media object with anvil.js.to_media()

Here’s a clone with a record and stop button that then downloads the audio recorded from the device.
(You could send the media object to the server instead)
https://anvil.works/build#clone:IT3K7PDMJVXPT33R=JUO5SOJ5NG7OR7GGIPKTUTIC

And the code
from anvil.js.window import navigator, MediaRecorder
import anvil.js

class Form1(Form1Template):
  def __init__(self, **properties):
    # Set Form properties and Data Bindings.
    self.init_components(**properties)
    self.stream = self.get_stream()
    self.media_recorder = MediaRecorder(self.stream)
    self.chunks = []
    self.media_recorder.ondataavailable = self.on_data_available
    self.media_recorder.onstop = self.on_stop
    # Any code you write here will run when the form opens.

  def record_button_click(self, **event_args):
    """This method is called when the button is clicked"""
    state = self.media_recorder.state
    print(state)
    
    if state == 'inactive':
      self.media_recorder.start()
      self.record_button.icon = 'fa:stop'
      self.record_button.text = 'Stop'
      self.record_button.role = 'secondary-color'
    else:
      self.media_recorder.stop()
      self.record_button.icon = 'fa:microphone'
      self.record_button.text = 'Record'
      self.record_button.role = 'primary-color'

  def get_stream(self):
    if navigator.mediaDevices and navigator.mediaDevices.getUserMedia:
      print('getUserMedia supported')
      return navigator.mediaDevices.getUserMedia({"audio": True})
    else:
      alert('media recording not supported')
  
  def on_data_available(self, e):
    self.chunks.append(e.data)
  
  def on_stop(self, e):
    media = anvil.js.to_media(self.chunks, name="recording")
    self.chunks = []
    download(media)
6 Likes

Thank you for your awesome reply!

I don’t want to complain to much but I feel a bit frustrated with Anvil. I came to Anvil with the promise (or at least the idea) to avoid having to learn JS and HTML… I don’t have the time right now. Why is this work around necessary though? I probably suck at reading documentation but I can’t even get it to replay the recording, let alone send it off to my cloud storage.

A possibly unsatisfactory answer is that browser technology is constantly evolving. The MediaRecorder api was only added to safari in April (for example).

Requests from the forum are a good way for us to keep track of where to improve and develop anvil.

as for playing the audio - I’ve now adjusted the clone link above to include a simple audio component you can use to playback the recording.

In terms of sending it to your cloud storage. That’s probably a separate question about how to work with an anvil media object and send it to the cloud storage you’re working with.

@stucork I would just like to say thank you for this little gadget that you have built here! Also thanks to the whole Anvil team. The stuff I find on the forum never cease to amaze me and I’m extremely happy with what you have created here! I never knew that you could do all this with only Python!
Awesome work everyone. Now let’s go out there and build cool stuff!

I am getting the following error on Chrome when I run the sample app.

ExternalError: NotAllowedError: Permission denied

  • at Form1, line 38
  • called from Form1, line 12

Ignore this please. When I run the code it gives this error but if I use the published url I don’t get the error.

2 Likes