You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Socket.IO+Ionic4实时音频流服务ALSA崩溃问题修复咨询

修复实时音频流服务ALSA崩溃问题

从你的报错信息和代码来看,核心问题是音频播放资源泄漏——服务端重复创建播放实例却未清理旧资源,导致ALSA/PulseAudio的设备连接被耗尽,最终无法打开音频设备。同时你的播放逻辑也没有正确处理实时传入的音频帧,而是在重复播放初始缓冲区内容。下面是具体的修复方案:

1. 问题根源分析

  • 原服务端代码在counter == 0时创建了一个无限循环的setTimeout,每次循环都会新建play实例,旧实例未被销毁,持续占用音频设备资源,直到设备无法处理新连接。
  • 客户端发送的是PCM_16BIT格式的Int16Array数据,服务端直接用Float32Array接收,未做格式转换,会导致音频数据失真,也可能触发播放异常。
  • 没有在客户端断开时清理播放资源,残留的资源会持续占用设备。

2. 修复后的服务端代码

let app = require('express')();
let http = require('http').Server(app);
let io = require('socket.io')(http);
let audioContext = require('audio-context')({
  sampleRate: 8000,
  latencyHint: 'balanced'
});
let buff = require('audio-buffer');

// 匹配客户端的缓冲区配置
const bufferSize = 8192;
var audioBuffer = new buff(audioContext, {
  length: bufferSize,
  sampleRate: 8000,
  numberOfChannels: 1
});

// 复用播放源,避免重复创建资源
let playbackSource = null;

// 将客户端的Int16格式PCM转换为Web Audio需要的Float32格式
function int16ToFloat32(inputArray) {
  let outputArray = new Float32Array(inputArray.length);
  for (let i = 0; i < inputArray.length; i++) {
    // Int16范围是-32768到32767,转换为Float32的-1到1区间
    outputArray[i] = inputArray[i] / 32768;
  }
  return outputArray;
}

io.on('connection', (socket) => {
  console.log('客户端已连接');

  socket.on('message', (data) => {
    console.log(data);
  });

  socket.on('audioinput', (data) => {
    // 转换音频数据格式
    const float32Data = int16ToFloat32(new Int16Array(data));
    
    // 更新缓冲区内容
    audioBuffer.copyToChannel(float32Data, 0, 0);

    // 停止旧的播放源(如果存在)
    if (playbackSource) {
      playbackSource.stop();
    }

    // 创建新的播放源并播放当前缓冲区
    playbackSource = audioContext.createBufferSource();
    playbackSource.buffer = audioBuffer;
    playbackSource.connect(audioContext.destination);
    playbackSource.start();

    // 播放结束后释放资源
    playbackSource.onended = () => {
      playbackSource = null;
    };
  });

  socket.on('disconnect', () => {
    console.log('客户端已断开');
    // 客户端断开时清理播放资源
    if (playbackSource) {
      playbackSource.stop();
      playbackSource = null;
    }
  });
});

var port = process.env.PORT || 6500;
http.listen(port, () => {
  console.log('服务启动,监听端口 ' + port);
});

3. 关键修改说明

  • 格式转换:新增int16ToFloat32函数,将客户端发送的PCM_16BIT数据转换为Web Audio API要求的Float32格式,避免数据错误。
  • 资源复用与清理:不再创建无限循环的定时器,每次收到音频数据时停止旧播放源,创建新播放源并播放当前缓冲区,播放结束后主动释放资源。
  • 断开清理:客户端断开连接时,主动停止播放源并释放资源,避免残留资源占用音频设备。

4. 额外优化建议

  • 调整缓冲区大小:8192的缓冲区在8000采样率下时长约1秒,可适当减小到4096或2048,降低延迟的同时减少单次播放的资源占用。
  • 实现音频队列:如果需要更流畅的播放,可以构建音频帧队列,当队列有足够帧时连续播放,避免频繁创建播放源。
  • 检查音频服务状态:确保服务器上的PulseAudio服务正常运行,可通过pulseaudio --start启动服务,或切换到ALSA直接输出。
  • 添加错误捕获:给audioContext和播放源添加错误监听,避免未处理的错误导致进程崩溃。

内容的提问来源于stack exchange,提问作者Азат Алиуллин

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:50:42