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

如何从无浏览器的无头RPi通过WebRTC推流音视频?基于Node.js适配iOS

无头树莓派基于Node.js+WebRTC推流实现方案(适配iOS)

整体技术选型

弃用uv4l方案,采用wrtc(Node.js原生WebRTC绑定库)作为核心实现,无需浏览器环境即可在无头树莓派上运行WebRTC协议栈。视频采集用树莓派官方的libcamera-vid/raspivid工具,音频采集用arecord,信令服务基于socket.io实现,完全自主可控可适配iOS兼容性要求。

树莓派环境准备

  • 安装基础依赖:
sudo apt update && sudo apt install -y libcamera-dev libasound2-dev build-essential
  • 安装Node.js 16/18 LTS版本,该版本对wrtc兼容性最好
  • 安装项目依赖,优先选择预编译的arm架构版本避免编译失败:
npm install @roamhq/wrtc express socket.io socket.io-client

核心实现逻辑

1. 信令服务实现

负责交换SDP offer/answer和ICE候选,可直接部署在树莓派本地:

// server.js 信令服务代码
const express = require('express');
const http = require('http');
const { Server } = require('socket.io');
const app = express();
const server = http.createServer(app);
const io = new Server(server, { cors: { origin: "*" } });

io.on('connection', (socket) => {
  socket.on('offer', (data) => socket.to(data.receiverId).emit('offer', data));
  socket.on('answer', (data) => socket.to(data.senderId).emit('answer', data));
  socket.on('ice-candidate', (data) => socket.to(data.targetId).emit('ice-candidate', data));
});

server.listen(8080, () => console.log('信令服务运行在8080端口'));

2. 树莓派推流逻辑

运行在树莓派后台的无头进程,直接采集音视频并推流:

// stream.js 推流端代码
const { RTCPeerConnection, RTCSessionDescription, RTCIceCandidate, MediaStream, MediaStreamTrack } = require('@roamhq/wrtc');
const { spawn } = require('child_process');
const io = require('socket.io-client');

const socket = io('http://127.0.0.1:8080');
const pc = new RTCPeerConnection({ 
  iceServers: [{ urls: 'stun:stun.l.google.com:19302' }] 
});

// 采集H.264视频流,树莓派旧系统(Buster及之前)替换libcamera-vid为raspivid
const videoProcess = spawn('libcamera-vid', [
  '--inline', '--framerate', '30', '--width', '1280', '--height', '720', 
  '--codec', 'h264', '--profile', 'high', '--level', '4.1', '-o', '-'
]);
// 采集48kHz单声道音频,适配WebRTC标准
const audioProcess = spawn('arecord', [
  '-f', 'S16_LE', '-c', '1', '-r', '48000', '-D', 'default', '-'
]);

// 封装音视频轨道加入PeerConnection
const videoTrack = new MediaStreamTrack({
  kind: 'video',
  codec: 'H264',
  stream: videoProcess.stdout
});
const audioTrack = new MediaStreamTrack({
  kind: 'audio',
  codec: 'opus',
  stream: audioProcess.stdout
});
const stream = new MediaStream([videoTrack, audioTrack]);
pc.addTrack(videoTrack, stream);
pc.addTrack(audioTrack, stream);

// 信令交互逻辑
socket.on('offer', async (data) => {
  await pc.setRemoteDescription(new RTCSessionDescription(data.offer));
  const answer = await pc.createAnswer();
  await pc.setLocalDescription(answer);
  socket.emit('answer', { senderId: data.receiverId, receiverId: data.senderId, answer });
});

pc.on('icecandidate', (candidate) => {
  if (candidate) socket.emit('ice-candidate', { targetId: 接收端连接ID, candidate });
});

socket.on('ice-candidate', async (candidate) => {
  await pc.addIceCandidate(new RTCIceCandidate(candidate));
});

iOS兼容核心要点

视频编码必须采用H.264 High Profile 4.1及以下等级,iOS Safari仅支持该等级的硬解码,编码等级过高会出现黑屏
SDP中不得包含iOS不支持的H.264扩展特性,必要时可手动过滤SDP中的冗余参数,移除FEC、SVC等特性声明
必须包含至少一个音频轨道,即便业务不需要音频也要加入静音轨道,iOS Safari不支持仅包含视频的WebRTC流
ICE候选必须存在可达地址,iOS对ICE候选的校验比Chrome严格,无有效可达候选会直接断开连接
iOS播放端video标签必须添加playsinline属性,且播放动作需要在用户交互事件(如点击)中触发,否则会被系统禁止播放

启动流程

  1. 启动信令服务:node server.js
  2. 启动推流进程:node stream.js
  3. 前端页面连接信令服务发送offer,收到answer后即可完成WebRTC连接播放

内容的提问来源于stack exchange,提问作者janek

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 12:36:04