0

I'm building a Text-to-Speech (TTS) component in React, where I want to specify the audio output device using sinkId (e.g., a selected speaker). Despite setting sinkId on the audio element, the audio consistently plays through the default output device instead of the selected one.

In this setup, I'm using SpeechSynthesisUtterance to generate TTS playback, and I tried routing the audio through an AudioContext with a MediaStreamDestination to control the output. However, sinkId does not seem to take effect. Any suggestions for correctly setting the output device?

example code :

import { useEffect, useRef, useState } from "react";
import { useDispatch, useSelector } from "react-redux";

const UseTTS = () => {
    const [isSpeaking, setSpeaking] = useState(false);
    const [isPaused, setIsPaused] = useState(false);

    const audioContextRef = useRef(null);
    const audioElement = useRef(null);
    const utteranceRef = useRef(null);

    const { selectedSpeakerSrc } = useSelector(state => state.setup);

    useEffect(() => {
        // Initialize AudioContext and audio element
        if (!audioContextRef.current) {
            audioContextRef.current = new (window.AudioContext || window.webkitAudioContext)();
        }
        if (!audioElement.current) {
            audioElement.current = new Audio();
        }
    }, []);

    const handlePlay = async () => {
        const ttsText = "Hello, this is a test message!";
        
        if (!utteranceRef.current) {
            utteranceRef.current = new SpeechSynthesisUtterance(ttsText);
            utteranceRef.current.lang = 'en-US';
            utteranceRef.current.onend = handleSpeechEnd;
        }

        try {
            if (audioElement.current.setSinkId && selectedSpeakerSrc) {
                await audioElement.current.setSinkId(selectedSpeakerSrc);
            }
        } catch (error) {
            console.error(`Failed to set sinkId: ${error}`);
        }

        utteranceRef.current.voice = speechSynthesis.getVoices()[0];
        speechSynthesis.speak(utteranceRef.current);
        setSpeaking(true);
    };

    const handleSpeechEnd = () => {
        setSpeaking(false);
        utteranceRef.current = null;
    };

    return {
        isSpeaking,
        handlePlay,
    };
};

export default UseTTS;

2

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.