JSFiddle - React, Tailwind, and code Playground

by juberti

HTML

<!DOCTYPE html>
<script type="worklet">
registerProcessor('my-processor', class param extends AudioWorkletProcessor {
  process(inputs, outputs, parameters) {
    const input = inputs[0];
    const output = outputs[0];

    for (let channel = 0; channel < input.length; ++channel) {
      const inputChannel = input[channel];
      const outputChannel = output[channel];

      for (let i = 0; i < inputChannel.length; ++i) {
        outputChannel[i] = inputChannel[i];
      }
    }

    // Copy the input data to a new Float32Array
    const data = new Float32Array(input[0]);

    // Post the data back to the main thread
    this.port.postMessage(data);

    return true;
  }
});
</script>
<button onclick="start()">Start</button>
<button onclick="stop()">Stop</button>
<br>
<textarea cols="80" id="output"></textarea>

JavaScript

var workerBlob = new Blob([
  document.querySelector('script[type=worklet]').textContent
], {
  type: "text/javascript"
});

class gladiaSpeechRecognition { //extends SpeechRecognition {
  constructor() {
    //super();
    this.interimResults = true;
    this.continuous = false;
  }
  async start() {
    this.context = new window.AudioContext();
    this.context.audioWorklet.addModule(window.URL.createObjectURL(workerBlob));
    this.socket = new WebSocket("wss://api.gladia.io/audio/text/audio-transcription");
    this.socket.binaryType = 'arraybuffer';
    this.socket.onopen = () => {
      this.socket.send(JSON.stringify({
        "x_gladia_key": "9832d309-1dba-4d3f-a68f-4cbabe4347c4",
        "sample_rate": this.context.sampleRate,
        "encoding": "wav"
      }));
    }
    this.socket.onmessage = message => {
    	var result = JSON.parse(message.data);
      if (result.transcription) {
	      console.log(`${result.type}: ${result.transcription}`);
        output.value = result.transcription;
      }
    }
    this.micStream = await navigator.mediaDevices.getUserMedia({
      audio: true
    });
    const sampleRate = this.context.sampleRate;
    const source = this.context.createMediaStreamSource(this.micStream);
    this.processorNode = new AudioWorkletNode(this.context, 'my-processor');
    this.processorNode.port.onmessage = event => {
      if (this.socket.readyState != 1) {
        //console.log(this.socket.readyState);
        return;
      }
      const chunk = this.makeWavChunk(event.data, );
      var base64 = btoa(String.fromCharCode.apply(null, new Uint8Array(chunk)));
      //console.log("sending chunk: " + base64);
      this.socket.send(JSON.stringify({
        "frames": base64
      }));
    };
    source.connect(this.processorNode).connect(this.context.destination);
  }

  abort() {
    this.socket.close();
    this.processorNode.disconnect();
    this.micStream.getTracks().forEach(track => track.stop());
    this.context.close();
   ...