14

Używam Google Cloud API do konwersji tekstu na tekst z zapleczem NodeJS. Aplikacja musi być w stanie nasłuchiwać poleceń głosowych i przekazywać je do zaplecza jako bufor. W tym celu muszę wysłać bufor poprzedniego audio po wykryciu ciszy.Jak wyodrębnić poprzedni dźwięk (z mikrofonu) jako bufor po wykryciu ciszy (JS)?

Każda pomoc zostanie doceniona. W tym kod js poniżej

if (!navigator.getUserMedia) 
    navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || 
     navigator.mozGetUserMedia || navigator.msGetUserMedia; 

if (navigator.getUserMedia) { 
    navigator.getUserMedia({audio: true}, success, function (e) { 
     alert('Error capturing audio.'); 
    }); 
} else alert('getUserMedia not supported in this browser.'); 

var recording = false; 

window.startRecording = function() { 
    recording = true; 
}; 

window.stopRecording = function() { 
    recording = false; 
    // window.Stream.end(); 
}; 

function success(e) { 
    audioContext = window.AudioContext || window.webkitAudioContext; 
    context = new audioContext(); 

    // the sample rate is in context.sampleRate 
    audioInput = context.createMediaStreamSource(e); 

    var bufferSize = 4096; 
    recorder = context.createScriptProcessor(bufferSize, 1, 1); 

    recorder.onaudioprocess = function (e) { 
     if (!recording) return; 
     console.log('recording'); 
     var left = e.inputBuffer.getChannelData(0); 
     console.log(convertoFloat32ToInt16(left)); 
     }; 

    audioInput.connect(recorder); 
    recorder.connect(context.destination); 
} 
+0

Nie wiem, w czym potrzebujesz pomocy: Przesyłanie danych do tego interfejsu API? Wykryć ciszę? Podziel swoje nagrane dane? – Kaiido

+0

Wysyłanie danych do tego interfejsu API i uzyskiwanie danych wyjściowych w czasie rzeczywistym. – azhar

+0

@azhar Czy interfejs API obsługuje komunikację w czasie rzeczywistym? – guest271314

Odpowiedz

2

Można użyć SpeechRecognitionresult zdarzenia do ustalenia, kiedy słowo lub wyrażenie zostało uznane, na przykład ls, cd, pwd lub innych poleceń, przekaż .transcript z SpeechRecognitionAlternative do speechSynthesis.speak() gdzie co dołączone start i end zdarzenie SpeechSynthesisUtterance zadzwoń pod .start() lub .resume() na MediaRecorder obiekt, gdzie przekazano MediaStream; przekonwertuj zdarzenie Blob pod dataavailable na ArrayBuffer, używając FileReader lub Response.arrayBuffer().

Mogliśmy alternatywnie użyć audiostart lub soundstart z audioend lub soundend wydarzeń SpeechRecognition nagrać rzeczywisty głos użytkowników, choć końce nie mogą być opalane konsekwentnie w stosunku do faktycznego rozpoczęcia i zakończenia audio przechwycone przez tylko standardowym systemie mikrofon.

<!DOCTYPE html> 
<html> 

<head> 
    <title>Speech Recognition Recording</title> 
</head> 

<body> 
    <input type="button" value="Stop speech command recognition" id="stop"> 
    <script> 
    navigator.mediaDevices.getUserMedia({ 
     audio: true 
     }) 
     .then(stream => { 
     const recorder = new MediaRecorder(stream); 
     const recognition = new webkitSpeechRecognition(); 
     const synthesis = new SpeechSynthesisUtterance(); 
     const handleResult = e => { 
      recognition.onresult = null; 
      console.log(e.results); 
      const result = e.results[e.results.length - 1]; 

      if (result.isFinal) { 
      const [{transcript}] = result; 
      console.log(transcript); 
      synthesis.text = transcript; 
      window.speechSynthesis.speak(synthesis); 
      } 
     } 
     synthesis.onstart =() => { 
      if (recorder.state === "inactive") { 
      recorder.start() 
      } else { 
      if (recorder.state === "paused") { 
       recorder.resume(); 
      } 
      } 
     } 
     synthesis.onend =() => { 
      recorder.pause(); 
      recorder.requestData(); 
     } 
     recorder.ondataavailable = async(e) => { 
      if (stream.active) { 
      try { 
       const blobURL = URL.createObjectURL(e.data); 
       const request = await fetch(blobURL); 
       const ab = await request.arrayBuffer(); 
       console.log(blobURL, ab); 
       recognition.onresult = handleResult; 
       // URL.revokeObjectURL(blobURL); 
      } catch (err) { 
       throw err 
      } 
      } 
     } 
     recorder.onpause = e => { 
      console.log("recorder " + recorder.state); 
     } 
     recognition.continuous = true; 
     recognition.interimResults = false; 
     recognition.maxAlternatives = 1; 
     recognition.start(); 
     recognition.onend = e => { 
      console.log("recognition ended, stream.active", stream.active); 

      if (stream.active) { 
      console.log(e); 
      // the service disconnects after a period of time 
      recognition.start(); 
      } 
     } 
     recognition.onresult = handleResult; 

     stream.oninactive =() => { 
      console.log("stream ended"); 
     } 

     document.getElementById("stop") 
      .onclick =() => { 
      console.log("stream.active:", stream.active); 
      if (stream && stream.active && recognition) { 
       recognition.abort(); 
       recorder.stop(); 
       for (let track of stream.getTracks()) { 
       track.stop(); 
       } 
       console.log("stream.active:", stream.active); 
      } 
      } 

     }) 
     .catch(err => { 
     console.error(err) 
     }); 
    </script> 
</body> 

</html> 

plnkr https://plnkr.co/edit/4DVEg6mhFRR94M5gdaIp?p=preview

+0

'webkitSpeechRecognition' powinno to działać tylko w chrome. Chcę to również w przeglądarkach bez Chrome. – azhar

+0

Więc próbuję użyć api google chmura Google w backend i analizować mowę do tekstu. Ale to, jak przesyłać głos z przedniego końca do końca, to mój problem. – azhar

+0

@azhar _ "Chcę tego również w przeglądarkach bez chrome" _ Jednym ze sposobów byłoby użycie dwóch elementów '

2

Najprostszym rozwiązaniem byłoby użyć .pause() i .resume(), .stop() metod MediaRecorder() aby umożliwić użytkownikowi na start, pauza i stop nagrywania audio przechwycone wykorzystując navigator.mediaDevices.getUserMedia() i konwertować wynikowy Blob do ArrayBuffer, jeśli to właśnie api oczekuje na POST ed na serwer

<!DOCTYPE html> 
<html> 

<head> 
    <title>User Media Recording</title> 
</head> 

<body> 
    <input type="button" value="Start/resume recording audio" id="start"> 
    <input type="button" value="Pause recording audio" id="pause"> 
    <input type="button" value="Stop recording audio" id="stop"> 
    <script> 
    navigator.mediaDevices.getUserMedia({ 
     audio: true 
     }) 
     .then(stream => { 
     const recorder = new MediaRecorder(stream); 

     recorder.ondataavailable = async(e) => { 
      if (stream.active) { 
      try { 
       const blobURL = URL.createObjectURL(e.data); 
       const request = await fetch(blobURL); 
       const ab = await request.arrayBuffer(); 
       // do stuff with `ArrayBuffer` of recorded audio 
       console.log(blobURL, ab); 
       // we do not need the `Blob URL`, we can revoke the object 
       // URL.revokeObjectURL(blobURL); 
      } catch (err) { 
       throw err 
      } 
      } 
     } 
     recorder.onpause = e => { 
      console.log("recorder " + recorder.state); 
      recorder.requestData(); 
     } 

     stream.oninactive =() => { 
      console.log("stream ended"); 
     } 

     document.getElementById("start") 
      .onclick =() => { 

      if (recorder.state === "inactive") { 
       recorder.start(); 
      } else { 
       recorder.resume(); 
      } 
      console.log("recorder.state:", recorder.state); 
      } 

     document.getElementById("pause") 
      .onclick =() => { 

      if (recorder.state === "recording") { 
       recorder.pause(); 
      } 
      console.log("recorder.state:", recorder.state); 
      } 

     document.getElementById("stop") 
      .onclick =() => { 

      if (recorder.state === "recording" || recorder.state === "paused") { 
       recorder.stop(); 
      } 

      for (let track of stream.getTracks()) { 
       track.stop(); 
      } 

      document.getElementById("start").onclick = null; 
      document.getElementById("pause").onclick = null; 
      console.log("recorder.state:", recorder.state 
      , "stream.active", stream.active); 
      } 

     }) 
     .catch(err => { 
     console.error(err) 
     }); 
    </script> 
</body> 

</html> 

plnkr https://plnkr.co/edit/7caWYMsvub90G6pwDdQp?p=preview

8

Nie jestem zbyt pewien, co dokładnie jest zadawane w pytaniu, więc ta odpowiedź ma jedynie na celu wykrycie ciszy w strumieniu audio.


celu wykrycia ciszy w AudioStream, można użyć AudioAnalyser węzeł, na którym będzie wywołać metodę getByteFrequencyData w regularnych odstępach czasu, i sprawdzić, czy nie było dźwięki wyższe niż niż oczekiwanego poziomu dla danego czasu.

Możesz ustawić poziom progu bezpośrednio za pomocą właściwości minDecibels węzła AnalyserNode.

function detectSilence(
 
    stream, 
 
    onSoundEnd = _=>{}, 
 
    onSoundStart = _=>{}, 
 
    silence_delay = 500, 
 
    min_decibels = -80 
 
) { 
 
    const ctx = new AudioContext(); 
 
    const analyser = ctx.createAnalyser(); 
 
    const streamNode = ctx.createMediaStreamSource(stream); 
 
    streamNode.connect(analyser); 
 
    analyser.minDecibels = min_decibels; 
 

 
    const data = new Uint8Array(analyser.frequencyBinCount); // will hold our data 
 
    let silence_start = performance.now(); 
 
    let triggered = false; // trigger only once per silence event 
 

 
    function loop(time) { 
 
    requestAnimationFrame(loop); // we'll loop every 60th of a second to check 
 
    analyser.getByteFrequencyData(data); // get current data 
 
    if (data.some(v => v)) { // if there is data above the given db limit 
 
     if(triggered){ 
 
     triggered = false; 
 
     onSoundStart(); 
 
     } 
 
     silence_start = time; // set it to now 
 
    } 
 
    if (!triggered && time - silence_start > silence_delay) { 
 
     onSoundEnd(); 
 
     triggered = true; 
 
    } 
 
    } 
 
    loop(); 
 
} 
 

 
function onSilence() { 
 
    console.log('silence'); 
 
} 
 
function onSpeak() { 
 
    console.log('speaking'); 
 
} 
 

 
navigator.mediaDevices.getUserMedia({ 
 
    audio: true 
 
    }) 
 
    .then(stream => { 
 
    detectSilence(stream, onSilence, onSpeak); 
 
    // do something else with the stream 
 
    }) 
 
    .catch(console.error);

I as a fiddle od stackSnippets mogą blokować dziąseł.