1

I'm building a React web app that uses the Web Speech API (SpeechRecognition) to detect a wake word (like "Hey Wiz") from the user’s microphone input.
The functionality works perfectly in desktop web browsers like Chrome — I get the transcript, and the wake word is detected as expected.
However, on mobile browsers (Chrome on Android and Safari on iOS), even though:

  • Microphone permission is granted,

  • No critical errors are thrown,

  • The logs show that SpeechRecognition started successfully,

  • …the onresult event never fires, and no voice input is captured.

    **LOGS
    **
    Speech recognition language set to: en-US  
    Starting speech recognition...  
    Wake word listener started successfully  
    Speech recognition error: aborted  
    Speech recognition aborted  
    Speech recognition ended  
    Speech recognition started successfully

const startWakeWordListener = (wakeWord: string, onWakeDetected: () => void) => {
  // Check browser compatibility
  const SpeechRecognition =
    window.SpeechRecognition ||
    window.webkitSpeechRecognition ||
    (window as any).msSpeechRecognition;

  if (!SpeechRecognition) {
    alert("Speech recognition is not supported in this browser");
    return;
  }

  // Request microphone permission with better error handling
  const requestMicrophoneAccess = async () => {
    try {
      console.log("Requesting microphone access...");
      // First try with basic constraints
      const basicConstraints = { audio: true };
      console.log("Trying basic audio constraints:", basicConstraints);
      const stream = await navigator.mediaDevices.getUserMedia(basicConstraints);
      mediaStream.current = stream;
      console.log("Microphone access granted successfully with basic constraints");
      // Now enumerate devices to see what we got
      const devices = await navigator.mediaDevices.enumerateDevices();
      const audioDevices = devices.filter(device => device.kind === 'audioinput');
      console.log("Available audio devices after permission:", audioDevices);

      return true;
    } catch (error: any) {
      console.error("Basic microphone access failed:", error);
      // Try with more specific constraints
      try {
        const specificConstraints = {
          audio: {
            echoCancellation: true,
            noiseSuppression: true,
            autoGainControl: true,
            sampleRate: 16000
          }
        };
        console.log("Trying specific audio constraints:", specificConstraints);
        const stream = await navigator.mediaDevices.getUserMedia(specificConstraints);
        mediaStream.current = stream;
        console.log("Microphone access granted successfully with specific constraints");
        return true;
      } catch (specificError: any) {
        console.error("Specific microphone access also failed:", specificError);

        // Handle specific error types
        if (specificError.name === 'NotFoundError' || specificError.name === 'DevicesNotFoundError') {
          console.error("No microphone device found");
          alert("No microphone device found. Please connect a microphone and refresh the page.");
        } else if (specificError.name === 'NotAllowedError' || specificError.name === 'PermissionDeniedError') {
          console.error("Microphone permission denied");
          alert("Microphone permission denied. Please allow microphone access in your browser settings and refresh the page.");
        } else if (specificError.name === 'NotReadableError' || specificError.name === 'TrackStartError') {
          console.error("Microphone is already in use");
          alert("Microphone is already in use by another application. Please close other applications using the microphone and try again.");
        } else if (specificError.name === 'OverconstrainedError' || specificError.name === 'ConstraintNotSatisfiedError') {
          console.error("Microphone constraints not satisfied");
          alert("Microphone constraints not satisfied. Please check your microphone settings.");
        } else {
          console.error("Unknown microphone error:", specificError);
          alert(Microphone error: ${specificError.message || 'Unknown error'}. Please check your microphone settings and try again.);
        }
        return false;
      }
    }
  };

  // Start the wake word listener process
  const initializeWakeWordListener = async () => {
    console.log("Initializing wake word listener...");
    const hasAccess = await requestMicrophoneAccess();
    if (!hasAccess) {
      console.error("Failed to get microphone access");
      return;
    }

    try {
      console.log("Creating speech recognition instance...");
      const recognitionInstance = new SpeechRecognition();
      recognitionInstance.continuous = true;
      recognitionInstance.interimResults = true;

      const languageCode = selectedLanguage.replace("_", "-");
      recognitionInstance.lang = languageCode;
      console.log("Speech recognition language set to:", languageCode);

      accumulatedTranscript.current = "";

      recognitionInstance.onsoundstart = () => {
        console.log("Sound detected - wake word listener is active");
        setIsNotValid(false);
      };

      recognitionInstance.onsoundend = () => {
        console.log("Sound ended");
      };

      recognitionInstance.onstart = () => {
        console.log("Speech recognition started successfully");
        setIsWakeWordListenerActive(true);
      };

      recognitionInstance.onresult = (event: any) => {
        let fullTranscript = "";

        for (let i = event.resultIndex; i < event.results.length; i++) {
          const transcript = event.results[i][0].transcript;
          fullTranscript += transcript + " ";
        }

        console.log('Wake word listener transcript:', fullTranscript);

        const cleanTranscript = fullTranscript.replace(/\s+/g, " ").trim().toLowerCase();
        console.log('Clean transcript:', cleanTranscript, 'Looking for:', wakeWord.toLowerCase());

        if (cleanTranscript.includes(wakeWord.toLowerCase())) {
          console.log(Wake word "${wakeWord}" detected!);
          recognitionInstance.stop();
          onWakeDetected(); // ⬅️ Call your bot/show logic here
        }
      };

      recognitionInstance.onend = () => {
        console.log("Speech recognition ended456");
        setIsWakeWordListenerActive(false);
        if (isRecording) {
          try {
            console.log("Restarting speech recognition...");
            recognitionInstance.start(); // Auto-restart
          } catch (e) {
            console.warn("Could not restart recognition:", e);
          }
        }
      };

      recognitionInstance.onerror = (event: any) => {
        console.error("Speech recognition error:", event.error);

        // Handle specific speech recognition errors
        if (event.error === 'no-speech') {
          console.log("No speech detected, continuing to listen...");
        } else if (event.error === 'audio-capture') {
          console.error("Audio capture error - microphone may be unavailable");
          alert("Audio capture error. Please check your microphone connection and try again.");
        } else if (event.error === 'network') {
          console.error("Network error in speech recognition");
          alert("Network error in speech recognition. Please check your internet connection.");
        } else if (event.error === 'not-allowed') {
          console.error("Speech recognition not allowed");
          alert("Speech recognition not allowed. Please check your browser permissions.");
        } else if (event.error === 'aborted') {
          console.log("Speech recognition aborted");
        } else {
          console.error("Unknown speech recognition error:", event.error);
        }
      };

      recognition.current = recognitionInstance;
      console.log("Starting speech recognition...");
      recognition.current.start();
      console.log("Wake word listener started successfully");
    } catch (error) {
      console.error("Error initializing wake word recognition:", error);
      alert("Error initializing wake word recognition. Please refresh the page and try again.");
    }
  };

  // Start the initialization process
  initializeWakeWordListener();

  // Add a timeout to check if wake word listener is working
  setTimeout(() => {
    if (!isWakeWordListenerActive) {
      console.warn("Wake word listener may not be working properly. Check microphone permissions and browser settings.");
    }
  }, 5000);
};
1
  • What exact process are you following to test your code? What is the phone doing when you run the test? Commented Jul 30 at 13:13

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.