0

I have implemented Web speech api in angular it is detecting the audio content but it throws this error :

core.js:6486 ERROR DOMException: Failed to execute 'start' on 'SpeechRecognition': recognition has already started. Angular Service:

import { Injectable } from '@angular/core';
    declare var webkitSpeechRecognition: any;
    
    @Injectable({
      providedIn: 'root'
    })
    export class VoiceRecognitionService {
    
      recognition =  new webkitSpeechRecognition();
      isStoppedSpeechRecog = false;
      public text = '';
      public tempWords : any;
      public transcript_arr = [];
      public confidence_arr = [];
    
    
      constructor() { }
    
      init() {
        this.recognition.continuous = true;
        this.recognition.interimResults = false;
        this.recognition.maxAlternatives = 1;
        this.recognition.lang = 'en-US';
    
    
        this.recognition.addEventListener('result', (e:any) => {
          let last = e.results.length - 1;
          let temp_trans = e.results[last][0].transcript; 
          this.transcript_arr.push(temp_trans); 
          const transcript = Array.from(e.results)
            .map((result:any) => result[0])
            .map((result) => result.transcript)
            .join(''); 
          this.tempWords = transcript;
        });
      }
    
      start() {
        this.isStoppedSpeechRecog = false;
        this.recognition.start();
        this.recognition.addEventListener('end', (condition:any) => {
          if (this.isStoppedSpeechRecog) {
            this.recognition.stop();
          } else {
            this.wordConcat()
            this.recognition.start();
          }
        });
      }
      stop() {
        this.isStoppedSpeechRecog = true;
        this.wordConcat();
        this.recognition.stop();
      }
      reinit()
      {
        this.transcript_arr = [];
        this.confidence_arr = [];
        this.tempWords='';
        this.text='';
      }
      wordConcat() {
        this.text = this.text + ' ' + this.tempWords + '.';
        this.tempWords = '';
      }
    }
user3653474
  • 3,393
  • 6
  • 49
  • 135
  • what does happen if you comment this line "this.recognition.start();"? try to keep one of them only. – Mahmoud Nasr Jan 26 '22 at 11:12
  • @MahmoudNasr : I have called end event listener in start function because i have to record sound continuouly before that it stops detecting if there is some idle time – user3653474 Jan 26 '22 at 11:15
  • @MahmoudNasr: if i place only these lines of code `this.isStoppedSpeechRecog = false; this.recognition.start();` then also i'm getting the same error – user3653474 Jan 26 '22 at 11:18
  • How this flag gets changed "this.isStoppedSpeechRecog", I can't see stop call in your code – Mahmoud Nasr Jan 26 '22 at 11:24
  • @MahmoudNasr I'm calling the service method from .ts file like `this.service.stop(); ` there is a stop() method in service that is being called to stop the service – user3653474 Jan 26 '22 at 11:31
  • Which browser you use? – Mahmoud Nasr Jan 26 '22 at 11:42
  • @MahmoudNasr : I'm using chrome browser getting this error when i stop this service and restart it again – user3653474 Jan 26 '22 at 11:44
  • please add your code scenario on stackblitz.com to get debug together :) – Mahmoud Nasr Jan 26 '22 at 12:05
  • @MahmoudNasr: Please check this link https://stackblitz.com/edit/angular-ivy-eyrgqz?file=src%2Fapp%2Fapp.module.ts if your audio is already started and then you click on start button then you will be getting error in your console – user3653474 Jan 27 '22 at 13:39
  • @MahmoudNasr : because of this error my other script on my page is not executed properly – user3653474 Jan 27 '22 at 13:40
  • check this I hope I didn't change your intended logic https://angular-ivy-ctpcgn.stackblitz.io https://stackblitz.com/edit/angular-ivy-ctpcgn?file=src/app/service/voice-recognition.service.ts – Mahmoud Nasr Jan 27 '22 at 14:25
  • @MahmoudNasr Getting same error ERROR DOMException: Failed to execute 'start' on 'SpeechRecognition': recognition has already started. if i click on start multiple times – user3653474 Jan 27 '22 at 14:39
  • I added a simple solution to that, I added a flag to disable the start button to prohibit the next clicks, and another flag in the service to assure the recognition.start executed once. https://angular-ivy-ctpcgn.stackblitz.io – Mahmoud Nasr Jan 27 '22 at 15:06
  • @MahmoudNasr: Thanks but in my case i have next and previous buttons i can't disable them user can go forward as well as backward is there any other way without disabling button? – user3653474 Jan 27 '22 at 15:22
  • you can remove the disable property from the button and it will still work properly, try it. – Mahmoud Nasr Jan 27 '22 at 15:27
  • @MahmoudNasr: I have checked but it stops recognizing after some time – user3653474 Jan 27 '22 at 16:01

1 Answers1

1

I added two different flags to manage both cases:

case 1: when the user stops the service.

case 2: when the service is stopped automatically.

import { Injectable } from '@angular/core';
declare var webkitSpeechRecognition: any;

@Injectable({
  providedIn: 'root',
})
export class VoiceRecognitionService {
  recognition = new webkitSpeechRecognition();
  isStoppedSpeechRecog = false;
  public text = '';
  tempWords: any;
  transcript_arr = [];
  confidence_arr = [];
  isStarted = false; //<< this Flag to check if the user stop the service
  isStoppedAutomatically = true; //<< this Flag to check if the service stopped automaticically.
  constructor() {}

  init() {
    this.recognition.continuous = true;
    this.recognition.interimResults = true;
    this.recognition.lang = 'en-US';

    this.recognition.addEventListener('result', (e: any) => {
      const transcript = Array.from(e.results)
        .map((result: any) => result[0])
        .map((result) => result.transcript)
        .join('');
      this.transcript_arr.push(transcript);
      this.tempWords = transcript;
      console.log(this.transcript_arr);

      const confidence = Array.from(e.results)
        .map((result: any) => result[0])
        .map((result) => result.confidence)
        .join('');
      this.confidence_arr.push(confidence);
      console.log(this.confidence_arr);
    });

    this.recognition.addEventListener('end', (condition: any) => {
      this.wordConcat();
      console.log('automatic!!');
      if (this.isStoppedAutomatically) {
        this.recognition.stop();
        this.recognition.start();
        this.isStoppedAutomatically = true;
      }
    });
  }

  start() {
    if (!this.isStarted) {
      this.recognition.start();
      this.isStarted = true;
      console.log('Speech recognition started');
    }
    return true;
  }
  stop() {
    if (this.isStarted) {
      this.isStoppedAutomatically = false;
      this.wordConcat();
      this.recognition.stop();
      this.isStarted = false;
      console.log('End speech recognition2');
    }
    return false;
  }

  wordConcat() {
    this.text = this.text + ' ' + this.tempWords + '.';
    this.tempWords = '';
  }
}

Check it running here

Mahmoud Nasr
  • 564
  • 7
  • 11
  • I have checked it but i stopped speaking for 10-15 sec then this speech recognition stopped – user3653474 Jan 28 '22 at 06:26
  • I modified the link. you may didn't check my answer code, it running with me for more than 10 minutes – Mahmoud Nasr Jan 28 '22 at 11:13
  • Thanks it is working, this service returns transcript after some delay so i if click on stop button so the last data is being shown after a few seconds of delay is there any way to display the last option will using observable resolve this issue – user3653474 Jan 31 '22 at 14:37