Web 应用程序中音频播放卡顿问题

问题描述 投票:0回答:1

我正在开发一个 Web 应用程序,它使用 WebRTC 和 Socket.IO 将音频从管理员实时传输到多个用户。但是,我遇到了一个问题,即用户端的音频播放断断续续或间歇性停止。以下是设置和问题的概述:

设置: 管理员使用 getUserMedia 和 MediaRecorder 从麦克风捕获音频。 使用lamejs将音频从WAV编码为MP3,并通过Socket.IO传输给用户。 用户接收音频块并尝试使用该元素播放它们。

问题:

虽然音频播放成功开始,但经常会在短时间内卡顿或停止。

管理员端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Admin Broadcasting</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/lamejs/1.2.0/lame.min.js"></script>
</head>
<body>
    <h1>Admin Broadcasting</h1>
    <button id="startBroadcastBtn">Start Broadcasting</button>
    
    <script src="/socket.io/socket.io.js"></script>
    <script>
        const startBroadcastBtn = document.getElementById('startBroadcastBtn');
        const socket = io('ws://localhost:9000');
        let mediaRecorder;

        startBroadcastBtn.addEventListener('click', async () => {
            try {
                const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
                if (!stream) {
                    console.error('getUserMedia failed to return a valid stream');
                    return;
                }

                // Initialize MediaRecorder with WAV format
                mediaRecorder = new MediaRecorder(stream);

                // Create WAV to MP3 converter using lamejs
                const mp3Encoder = new lamejs.Mp3Encoder(1, 44100, 128);

                // Add event listener for data availability
                mediaRecorder.ondataavailable = async (event) => {
                    try {
                        if (event.data.size > 0) {
                            console.log('Audio chunk captured:', event.data);

                            // Convert WAV audio data to MP3
                            const reader = new FileReader();
                            reader.onload = async () => {
                                const arrayBuffer = reader.result;
                                const buffer = new Int8Array(arrayBuffer);
                                const length = buffer.length;
                                const pcm = new Int16Array(length / 2);
                                
                                // Convert Int8Array to Int16Array (PCM data)
                                for (let i = 0; i < length; i += 2) {
                                    pcm[i / 2] = buffer[i] | (buffer[i + 1] << 8);
                                }

                                const mp3Data = mp3Encoder.encodeBuffer(pcm);
                                const mp3Blob = new Blob([mp3Data], { type: 'audio/mp3' });
                                console.log('Created MP3 blob:', mp3Blob);
                                socket.emit('admin-audio-chunk', mp3Blob);
                            };
                            reader.readAsArrayBuffer(event.data);
                        }
                    } catch (error) {
                        console.error('Error processing audio data:', error);
                    }
                };

                // Start recording
                console.log('Starting recording...');
                mediaRecorder.start(1000);
                console.log('Recording started.');
            } catch (error) {
                console.error('Error accessing media devices:', error);
            }
        });
    </script>
</body>
</html>

用户端代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>User Listening</title>
</head>
<body>
    <h1>User Listening</h1>
    <audio id="audioPlayer" controls preload="auto"></audio>

    <script src="/socket.io/socket.io.js"></script>
    <script>
        const audioPlayer = document.getElementById('audioPlayer');
        const socket = io('ws://localhost:9000');
        let audioChunks = [];

        socket.on('user-audio-chunk', (data) => {
            console.log('Received audio chunk from admin:', data);
            audioChunks.push(data);
            playAudioChunks();
        });

        function playAudioChunks() {
            if (audioChunks.length > 0 && audioPlayer.paused) {
                const audioBlob = new Blob(audioChunks, { type: 'audio/mp3' });
                audioPlayer.src = URL.createObjectURL(audioBlob);
                audioPlayer.play().catch((error) => {
                    console.error('Error playing audio:', error);
                });
                audioChunks = [];
            }
        }
    </script>
</body>
</html>

如何流畅播放音频并解决问题?

webrtc audio-streaming simplewebrtc mediarecorder-api
1个回答
0
投票

设置:管理员使用 getUserMedia 和 MediaRecorder 从麦克风捕获音频。使用lamejs将音频从WAV编码为MP3,并通过Socket.IO传输给用户。用户接收音频块并尝试使用该元素播放它们。

您正在编码块并播放块......所以这就是为什么您有厚实的声音音频。如果您想要音频流,您需要将其视为流。

不要每次都实例化新的编解码器。我不知道你的 LAME 版本如何,但常规 LAME 将利用位存储库,它将数据从一帧传输到另一帧。因此,您需要设置一个实例并不断向其推送 PCM 数据。

现在,在播放方面,根本不要使用 Web Sockets 之类的东西。比那更简单。使用简单的

<audio>
元素并通过 HTTP stream 数据:

<audio src="https://stream.example.com/something"></audio>

您的服务器应该获取它获得的块并立即将它们写入客户端。相反,如果您尝试单独解码每个片段,您只会得到解码的块,并且它们不会神奇地及时播放并排队。

最新问题
© www.soinside.com 2019 - 2024. All rights reserved.