头像无法启动。错误:InvalidCharacterError:无法在“Window”上执行“atob”:要解码的字符串未正确编码

问题描述 投票:0回答:1
// utilty.js
export const fetchIceCredentials = async () => {
    try {
        const response = await axios.get('https://westus2.tts.speech.microsoft.com/cognitiveservices/avatar/relay/token/v1', {
            headers: {
                'Ocp-Apim-Subscription-Key': cogSvcSubKey
            }
        });
        const { Username: iceUsername, Password: iceCredential } = response.data;
        if (!iceUsername || !iceCredential) {
            throw new Error('ICE credentials are missing');
        }
        if (iceUsername && iceCredential) {
            // Check base64 encoding
            if (!isValidBase64(iceCredential)) {
                console.error('ICE credential is not a valid base64 string:', iceCredential);
                console.error('ICE UserName is not a valid base64 string:', iceUsername);
                throw new Error('Invalid base64 encoding');
            } else{ 
                console.log('iceCredential is valid')
            return { iceUsername, iceCredential };
            }
        } else {
            throw new Error('Invalid credentials format');
        }
    } catch (error) {
        console.error('Error fetching ICE credentials:', error);
        throw error;
    }
};

export function isValidBase64(str) {
    const base64Regex = /^([A-Za-z0-9+/=]+)$/;

    if (!base64Regex.test(str)) {
        return false;
    }

    try {
        const decodedStr = atob(str);
        return btoa(decodedStr) === str;
    } catch (e) {
        return false;
    }
}


export const createWebRTCConnection = (iceServerUrl, iceServerUsername, iceServerCredential) => {
    try {
        const peerConnection = new RTCPeerConnection({
            iceServers: [{
                urls: [iceServerUrl],
                username: iceServerUsername,
                credential: iceServerCredential
            }]
        });
        return peerConnection;
    } catch (error) {
        console.error("Error creating WebRTC connection: ", error);
        throw error;
    }
};
 
export const createAvatarSynthesizer = () => {
    try {
        console.log("Initializing Speech SDK with:", cogSvcSubKey, cogSvcRegion, voiceName);
        const speechSynthesisConfig = SpeechSDK.SpeechConfig.fromSubscription(cogSvcSubKey, cogSvcRegion);
        speechSynthesisConfig.speechSynthesisVoiceName = voiceName;
 
        const videoFormat = new SpeechSDK.AvatarVideoFormat();
 
        const videoCropTopLeftX = 600;
        const videoCropBottomRightX = 1320;
        videoFormat.setCropRange(new SpeechSDK.Coordinate(videoCropTopLeftX, 50), new SpeechSDK.Coordinate(videoCropBottomRightX, 1080));
 
        console.log("Avatar configuration:", avatarCharacter, avatarStyle, avatarBackgroundColor);
        const avatarConfig = new SpeechSDK.AvatarConfig(avatarCharacter, avatarStyle, videoFormat);
        avatarConfig.backgroundColor = avatarBackgroundColor;
 
        const avatarSynthesizer = new SpeechSDK.AvatarSynthesizer(speechSynthesisConfig, avatarConfig);
 
        avatarSynthesizer.avatarEventReceived = (s, e) => {
            const offsetMessage = e.offset === 0 ? "" : `, offset from session start: ${e.offset / 10000}ms.`;
            console.log(`[${new Date().toISOString()}] Event received: ${e.description}${offsetMessage}`);
        };
 
        return avatarSynthesizer;
    } catch (error) {
        console.error("Error creating Avatar Synthesizer: ", error);
        throw error;
    }
};

// App.jsx--React 代码的一部分

// Fetch ICE credentials
        const { iceUsername, iceCredential } = await fetchIceCredentials();
        const iceUrl = avatarAppConfig.iceUrl;
        let peerConnection = createWebRTCConnection(iceUrl, iceUsername, iceCredential);
        peerConnection.ontrack = handleOnTrack;
        peerConnection.addTransceiver('video', { direction: 'sendrecv' });
        peerConnection.addTransceiver('audio', { direction: 'sendrecv' });
        console.log("WebRTC connection created.");

        let synthesizer = createAvatarSynthesizer();
        setAvatarSynthesizer(synthesizer);
        peerConnection.oniceconnectionstatechange = e => {
            console.log("WebRTC status: " + peerConnection.iceConnectionState);

            if (peerConnection.iceConnectionState === 'connected') {
                console.log("Connected to Azure Avatar service");
            } else if (peerConnection.iceConnectionState === 'disconnected' || peerConnection.iceConnectionState === 'failed') {
                console.log("Azure Avatar service Disconnected");
            }
        };
        synthesizer.startAvatarAsync(peerConnection).then((r) => {
            console.log("[" + (new Date()).toISOString() + "] Avatar started.");
            
        }).catch(async (error) => {
                console.error("[" + (new Date()).toISOString() + "] Avatar failed to start. Error: " + error);

            }
        );
    };

我收到错误为

Avatar failed to start. Error: InvalidCharacterError: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.

尝试访问该网页时,我总是遇到错误。刷新页面无法解决问题,因为错误仍然存在。有时,如果我等待 30-40 秒再刷新,页面会正确加载并显示头像。然而,这种解决方案并不可靠,因为错误经常发生。我无法确定此问题的根本原因,需要帮助诊断和解决它。

azure webrtc text-to-speech avatar
1个回答
0
投票

头像启动失败。错误:InvalidCharacterError:无法在“Window”上执行“atob”:要解码的字符串未正确编码。

您从 API 收到的凭据确实是有效的 base64 字符串。首先记录响应以查看您得到了什么。

  • 当前验证功能可能不够健壮,改进base64验证功能。
        // Check base64 encoding
        if (!isValidBase64(iceCredential)) {
            console.error('ICE credential is not a valid base64 string:', iceCredential);
            throw new Error('Invalid base64 encoding');
        } else if (!isValidBase64(iceUsername)) {
            console.error('ICE Username is not a valid base64 string:', iceUsername);
            throw new Error('Invalid base64 encoding');
        } else {
            console.log('ICE credentials are valid');
            return { iceUsername, iceCredential };
        }
    } catch (error) {
        console.error('Error fetching ICE credentials:', error);
        throw error;
    }

App.jsx:

import { useEffect, useState } from 'react';
import { fetchIceCredentials, createWebRTCConnection, createAvatarSynthesizer } from './utility';

const App = () => {
    const [avatarSynthesizer, setAvatarSynthesizer] = useState(null);

    useEffect(() => {
        const initialize = async () => {
            try {
                const { iceUsername, iceCredential } = await fetchIceCredentials();
                const iceUrl = avatarAppConfig.iceUrl;

                let peerConnection = createWebRTCConnection(iceUrl, iceUsername, iceCredential);
                peerConnection.ontrack = handleOnTrack;
                peerConnection.addTransceiver('video', { direction: 'sendrecv' });
                peerConnection.addTransceiver('audio', { direction: 'sendrecv' });
                console.log("WebRTC connection created.");

                let synthesizer = createAvatarSynthesizer();
                setAvatarSynthesizer(synthesizer);
                
                peerConnection.oniceconnectionstatechange = e => {
                    console.log("WebRTC status: " + peerConnection.iceConnectionState);

                    if (peerConnection.iceConnectionState === 'connected') {
                        console.log("Connected to Azure Avatar service");
                    } else if (peerConnection.iceConnectionState === 'disconnected' || peerConnection.iceConnectionState === 'failed') {
                        console.log("Azure Avatar service Disconnected");
                    }
                };
                
                synthesizer.startAvatarAsync(peerConnection).then((r) => {
                    console.log("[" + (new Date()).toISOString() + "] Avatar started.");
                }).catch((error) => {
                    console.error("[" + (new Date()).toISOString() + "] Avatar failed to start. Error: " + error);
                });
            } catch (error) {
                console.error("Error during initialization:", error);
            }
        };

        initialize();
    }, []);

    return (
        <div>
            {/* Your UI code here */}
        </div>
    );
};

export default App;
  • 有时,间歇性的网络问题可能会导致问题。保持稳定的网络连接。

结果:

[INFO] Initializing Speech SDK with: YOUR_COG_SVC_SUB_KEY YOUR_COG_SVC_REGION YOUR_VOICE_NAME
[INFO] Avatar configuration: YOUR_AVATAR_CHARACTER YOUR_AVATAR_STYLE YOUR_AVATAR_BACKGROUND_COLOR
[INFO] Fetching ICE credentials...
[INFO] ICE credentials are valid
[INFO] WebRTC connection created.
[INFO] WebRTC status: new
[INFO] WebRTC status: checking
[INFO] WebRTC status: connected
[INFO] Connected to Azure Avatar service
[INFO] [2024-08-01T12:34:56.789Z] Avatar started.
© www.soinside.com 2019 - 2024. All rights reserved.