# @babblevoice/projectrtp 中文文档

规范地址：https://npmcn.com/package/%40babblevoice/projectrtp/

版本：3\.7\.0
npm 元数据更新时间：2026-08-12T15:52:51.064Z
中文译文更新时间：2026-11-08T01:38:48.763Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40babblevoice/projectrtp
原文对照：https://npmcn.com/package/%40babblevoice/projectrtp/?lang=original
项目主页：https://github.com/babblevoice/projectrtp#readme
源码仓库：https://github.com/babblevoice/projectrtp

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：14.5 MB，1642 个文件
- 模块格式：CommonJS
- TypeScript 类型：未声明
- 运行依赖：1 个
- 首次发布：2022-06-17T12:00:31.211Z
- 最新版本发布：2026-08-12T15:52:50.853Z
- 近 30 天下载量：1934（2026-10-08 至 2026-11-06，npm 官方下载统计）
- 已发布版本数：88（近 12 个月 35 个）

## 中文简介

可缩放节点添加 RTP 服务器

## 安装

```sh
npm install @babblevoice/projectrtp
```

也可以使用：`pnpm add @babblevoice/projectrtp`、`yarn add @babblevoice/projectrtp`、`bun add @babblevoice/projectrtp`

## README

# 项目RTP

另见: [米兰特·姆德](https://npmcn.com/package/%40babblevoice/projectrtp/MIGRATE.md) [四、建 议](https://npmcn.com/package/%40babblevoice/projectrtp/ARCHITECTURE.md)

[![Build](https://github.com/babblevoice/projectrtp/actions/workflows/buildimage.yaml/badge.svg)](https://github.com/babblevoice/projectrtp/actions/workflows/buildimage.yaml)

一个 RTP 节点加通,提供处理 RTP 数据流并将其混合的功能. 所有表演任务都用Rust(一个sami-rs本土模块)执行,每个频道的tokio演员模型用于高通量.

ProjectRTP旨在被规模化为多个服务器,服务于其他信号服务器. RTP和信号传递应该分开,这种架构允许这样. 它得到一个代理服务器和客户端,以允许远程节点.

ProjectRTP旨在提供PBX所需的所有功能,包括通道连接,录音,回放和IVR所有必要功能.

特征

-   2+ 通道混合
-   CODEC 转换编码( 介于以下所列支持的CODECs之间)
-   电话录音(WAV)
    -   每个频道有多个录音机
    -   基于电源检测或命令的启动、暂停和结束
-   WAV 使用音汤描述播放从部件播放复杂句子的回放
-   混合 play+record( playrecord) 用于0- gap 即时录入可选驳入
    -   列车模式:能量 `interrupt` (粗放的入门切入快取),或 `concurrent` (在提示持续播放时记录答案) `stopplay()` 一旦答案可以接受,即以内容为主,而不是以能量为主)
-   DTMF(RFC 2833) - 发送、接收和接通
-   DTLS SRTP (WebRTC) (中文(简体) )
-   高度可缩放 - 服务器/节点解决方案以缩放媒体节点

## 版本编号

我们使用语义版本编号.

由于版本号为 MAJOR.MINOR.PATCH, 递增:

1.  当您进行不兼容的 API 修改时, maJOR 版本,
2.  MINOR 版本,当您以反向兼容的方式添加功能时,以及
3.  PATCH 版本,当您向后兼容错误修正时 .

作为这项工作的一部分,我们维护jsdoc文件,以记录我们与这一方案的公共界面.

## 释放过程

在 GitHub 动作上管理发布. 它建立和测试任何版本.

## 夹克

Amd64 和 arm64 的公用嵌入器图像可用 [多克枢纽](https://hub.docker.com/repository/docker/tinpotnick/projectrtp)。 。 。 .

## 测试

测试需要本地模块( libilbc + libspandsp), 因此最简单的路径是 Docker `test` 阶段。 当地, `npm run build` 生产 `build/Release/projectrtp.node` 从一箱起 `npm test` 用它来管理套房 `libilbc` 财务报告和审定财务报表 `libspandsp` 在主机上.

### 构建测试图像

```bash
docker build --target test -t projectrtp-test .
```

### 运行所有测试

```bash
docker run --rm projectrtp-test
```

图像的默认命令运行 `mocha test/interface/*.js test/unit/*.js --exit`。 。 。 .

注:套间用途 `test/interface/*.js` 财务报告和审定财务报表 `test/unit/*.js` -没有 `test/**/*.js` - 因为.. `test/basictests.js` 财务报告和审定财务报表 `test/codectests.js` 是独立的脚本(不是摩卡测试),如果被摩卡加载,会被悬挂.

### 运行特定测试

大部分测试文件都依赖于服务器测试( I)`projectrtpserver.js`)首先启用本地模块,因此在运行单个文件时包含:

```bash
docker run --rm projectrtp-test \
  ./node_modules/mocha/bin/_mocha \
  test/interface/projectrtpserver.js test/interface/projectrtpplayrecord.js \
  --exit --timeout 20000
```

### 测试本地编辑

挂载 `test/` 财务报告和审定财务报表 `lib/` 这样您就可以编辑和重运行而不重建本地模块 :

```bash
docker run --rm \
  -v ./test:/usr/src/projectrtp/test \
  -v ./lib:/usr/src/projectrtp/lib \
  projectrtp-test \
  ./node_modules/mocha/bin/_mocha \
  test/interface/projectrtpserver.js test/interface/projectrtpplayrecord.js \
  --exit --timeout 20000
```

如果您更改了 Rust 源文件, 请重建图像 .

### 粗口测试

箱子本身的单元测试是通过货物进行的:

```bash
npm run rust:test          # or: cd rust && cargo test --lib
```

### 压力测试

在荷载下的随机时间打开并关闭频道. 设计用于货币和赛跑条件测试——没有通关/故障,但会在不良行为上崩溃或产生出意料的输出.

```bash
docker run --rm projectrtp-test sh -c \
  "cd /usr/src/projectrtp && npm run stress"
```

### Mic 测试工具

`test/tools/mictest.js` 是一个CLI工具,用于手动测试真麦克风和扬声器的播放记录。 它需要当地土建(`npm run build`和 `sox` 在主机上 – 完整的构建依赖列表请参见 Dockerfile.

```bash
node test/tools/mictest.js [--prompt <file>] [--output <file>] [--duration <ms>] [--interrupt] [--bargeinpower <n>]
```

播放一个提示(或生成的测试语气),记录您的声音,实时打印事件,并保存到 `/tmp/mictest_recording.wav`。 。 。 .

## 示例脚本

示例文件夹包含使用此库的两个脚本 。 简单的节点可以在不需要特殊功能的地方被使用. 标准 projectp docker 图像指向此 - 因此启动一个 docker 实例会作为节点运行并尝试连接到一个中央控制服务器.

高级节点.js是一个包含前处理和后处理的范例——可以使用,例如下载录音,执行文字到演讲或完成后上传录音.

### 运行

环境变量HOST应包含控制服务器的主机地址-其默认为127.0.0.1. 可变 PORT 有端口号码可以通信 - 默认为9002.

环境变量 PA 采取以下形式——地址被传递回控制服务器,从而可以在SDP中发布——即允许在不同IP地址上设置多个RTP节点. 如果您不通过, 默认脚本将会通过调用来确定您的公共 IP 地址 [https://checkip.amazonaws.com (中文(简体) )](https://checkip.amazonaws.com/) 获取你的IP.

docker run -- restart= always --net=host -d -it --env PA=127.0.0.1 --name=prtp projectrtp:latest 互联网档案馆的存檔,存档日期2013-12-02

## 编解码器

ProjectRTP支持以下 CODEC 的转码

-   澳门
-   PCMU 电脑
-   G722集团
-   iLBC (英语)

## 使用量

2个示例脚本可见于示例文件夹. simplenode.js作为主条目被多克容器使用.

## 环境变量

这些在简单节点.js的例子中解析.

-   PORT - 要连接的端口
-   HOST - 要连接到的主机
-   PA - 这个主机的公开地址 - 它被传回到控制套接字上, 以便发布给客户端 - 如果没有脚本民调 [https://checkip.amazonaws.com (中文(简体) )](https://checkip.amazonaws.com/) 我们的公开演讲.

## 小示例

这个工程包含所有功能,可以用作本地资源或多个节点处理媒体. 在两个模式之间切换是无缝的. 在节点模式下使用时,它有一个简单的协议,可以在服务器和节点之间进行通信.

每个活动节点连接到主服务器,向主服务器提供服务. 然后主服务器打开任何可用的 RTP 频道(WebRTC 或普通 RTP). 所使用的协议可以在 /lib 文件中查看.

### 服务器示例

服务器通常在打开媒体端口之前运行应用程序逻辑.

```js

const prtp = require( "@babblevoice/projectrtp" ).projectrtp

/* This switches this server to a central
server and requires nodes to connect to us
to provide worker nodes */
await prtp.server.listen()

const codec = 9 /* G722 */

/*
When you have a node configured and connected to this server...

Now open our channel:
The remote comes from your client (web browser?)
including options for WebRTC if it is a web browser.
*/
let channela = await prtp.openchannel( {
      "remote": { address, port, codec }
      } )


let channelb = await prtp.openchannel( {
      "remote": { "address": otheraddress, "port": otherport, codec }
      } )

/*
Offer both of these channels to the remote clients (convert to SDP?)
*/

/* Ask projectrtp to mix the audio of both channels */
channela.mix( channelb )

/* Keep calling the mix function with other channels to create a conference */
```

我们可以换个方式 即指示控制服务器连接节点 我们可以增加多个节点,也可以使用一个道克星团作为一个发布多个节点.

```js

const prtp = require( "@babblevoice/projectrtp" ).projectrtp

const port = 9002
const host = "192.168.0.100"

prtp.server.addnode( { host, port } )

/*
When we need a channel now, the library will
make that request to one of our nodes.
*/
let channela = await prtp.openchannel( {
      "remote": { address, port, codec }
      } )

```

### 节点示例

节点是网络的工作马. 连接到服务器并等待指令 。 更多实例请参见示例文件夹,例如如何连接到事件中来履行诸如从存储中下载这样的S3等功能.

```js

const prtp = require( "@babblevoice/projectrtp" ).projectrtp

async function go() {

  prtp.run()

  prtp.node.listen( "0.0.0.0", 9002 )
  const pa = await wgets( "https://checkip.amazonaws.com" )

  prtp.setaddress( pa )

}

listen()

```

## 状态

当我们从我们的节点(或者如果站立龙只是我们自己)接收到一个对象时,该对象包含关于: s州. 它包括开放频道数量,MOS质量分数等项目.

MOS只包括我们收到的测量数据.

滴答时间是处理RTP数据在发送前需要的时间. 我们做一些工作 当我们发送和接收 RTP数据,但大多数工作都是用打勾完成的,这表明了负荷和能力.

测量是在US(即我们在命名公约中)。 在以上的例子中,平均时间为84uS。 在溪流的ptime(我们只用20mS的ptime)上发生一滴.

如果有多个频道被混合,它们都会得到与同一频道被混合的一样的打勾时间,这代表了所有频道的总时间.

### 播放

播放一个声音"soup"。 这是一个要播放的文件列表,可能包括要播放的文件的起止时间. 项目RTP 支持 wav 文件 。 一个例子汤:

```js

channel.play( {
  "soup": {
    "loop": true,
    "files": [
      { "wav": "filename.wav", "start": 1000, "stop": 4000 }
    ]
  }
} )

```

-   循环可以是真实的(连续的- well- INT MAX) 也可以是数字
-   循环可以是主汤(即通过所有文件循环),也可以是在一个文件(即通过这个文件循环了3次)上
-   文件名可以在param"wav","pcma","pcmu","l168k","l1616k","ilbc","g722"中出现. 见下文关于它们用途的说明,所有文件都载有该格式的文件名称(尚未完成).
-   启动 - 从( 可选的) 开始播放的 mS 数量
-   stop - 停止播放的 mS 数( 可选)

起止参数允许很多片段包含在同一文件中.

文件名可以包含在不同的参数中 。 如果您提供了参数, RTP 服务器将假设文件存在, 并且格式正确 。 使用此参数的目标是在播放一个文件时减少任何转码的CPU间接费用.

#### 其他汤的例子

队列通知

```js
channel.play( {
  "loop": true,
  "files": [
    { "wav": "ringing.wav", "loop": 6 },
    { "wav": "youare.wav" },
    { "wav": "first.wav" },
    { "wav": "inline.wav" }
  ]
} )
```

我们也许还合并了一些疯狂的文件:

```js
channel.play( {
  "loop": true,
  "files": [
    { "wav": "ringing.wav", "loop": 6 },
    { "wav": "youare.wav" },
    { "wav": "ordinals.wav", "start": 3000, "stop": 4500 },
    { "wav": "inline.wav" }
  ]
} )
```

### 记录

记录到一个文件。 ProjectRTP目前支持2个频道的PCM.

可以根据 projectrtp 选择: 文件 = - 要保存为 uuid= - 频道 uuuid 要记录

以秒为多至 MA 最大尺寸( 5 秒? ) , 默认为 1 秒 RMS 功率由每包计算,然后使用移动平均滤波器进行平均计算. 平均电源包=将平均电源窗口移到平均电源上

一定已经开始了 如果被忽略了 才刚刚开始 启动功率 =

何时完成 - 如果低于这一数额 完成以下功率 =

与完后功率结合使用 - 用于有功率阈值的相接 即在这个 mS 数通过之前, 功率低于完成的下限 心电图 = < int > mseconds

一定超乎意料 并设定了录音的尺寸限制 最大长度 = < int > mseconds

必须是一或二 数字通道 = < int > 计数

```js
channel.record( {
  "file": "/voicemail/greeting_1.wav",
  "maxduration": 10 * 1000 /* mS */,
  "numchannels": 1
} )
```

### 现场音频—— `channel.createReadStream`

返回标准节点 `Readable` 当频道接收/发送时, 发送解码音频缓冲器 。 使用此功能将音频输入到任何需要流出的东西中——STT,翻译,标题,WebSocket转发器,上磁盘抓取——而无需通过记录器/文件路径.

每个被排放块的字节形状固定在阅读器的寿命,并作为可读器的属性被曝光:

```js
const reader = channel.createReadStream( {
  direction:   "in",    // "in" (default) | "out" | "both"
  format:      "l16",   // "l16" (default) | "pcma" | "pcmu" | "g722" | "ilbc"
  samplerate:  8000,    // 8000 (default) | 16000  — only meaningful for l16
  numchannels: 1        // 1 (default) | 2  — stereo interleaves L=in R=out
} )

reader.format        // "l16"
reader.samplerate    // 8000
reader.numchannels   // 1
reader.direction     // "in"
reader.readerId      // monotonic id (handy for log correlation)

reader.on( "data", ( buf ) => { /* Buffer, one 20 ms frame */ } )
reader.on( "end",  () => {} )   // fires on channel close or reader.destroy()

reader.pipe( wsStream )         // standard Node stream composition
reader.destroy()                // explicit teardown
```

**方向**

-   `"in"` - 音频对等端发送我们,后解码。 你想要的STT/语音生物鉴别仪 在呼叫器.
-   `"out"` ——音频此频道正在发送(玩家,回声,或混合输出). 同行所闻.
-   `"both"` ——立体声,相接出,L=入,R=出. 要求数 `numchannels: 2`。 。 。 .

用于独立的每语源流( 如 diarized 标题), 创建 **两个读取器在同一频道** 一个 `direction: "in"`,一个 `direction: "out"`两道单流,两道独立的STT管线,它们之间没有接合.

**格式**

`"l16"` 按所选样本率给出线性PCM-16 LE——每个STT/翻译API接受的通用格式. 线条格式( E)`"pcma"`, (中文(简体) ), `"pcmu"`, (中文(简体) ), `"g722"`, (中文(简体) ), `"ilbc"`)提供原始的编码字节,当你想在别处转发一条腿而不重新编码时有用.

**后压和后降**

输油管从不会堵住20毫秒的RTP滴答. 如果消费者(或节点事件回路,或凝胶队列)落后,框被丢弃. 在实践中,只有在消费者真的被卡住的情况下才咬伤——典型的STT/WebSocket消费者舒适地跟上了20ms帧.

**示例——将一条腿插入WebSocket STT服务:**

```js
const reader = channel.createReadStream( { direction: "in", format: "l16", samplerate: 16000 } )
const ws = new WebSocket( "wss://stt.example.com/stream?rate=16000&format=l16" )

reader.on( "data", ( buf ) => ws.send( buf ) )
ws.on( "message", ( transcript ) => console.log( "→", transcript.toString() ) )

/* When the call ends the reader emits `end` and the ws.send loop quiets. */
reader.on( "end", () => ws.close() )
```

**示例 – 双声道呼叫录制分出每个频道 :**

```js
const caller = channel.createReadStream( { direction: "in" } )
const agent  = channel.createReadStream( { direction: "out" } )

caller.pipe( fs.createWriteStream( "/tmp/caller.pcm" ) )
agent.pipe(  fs.createWriteStream( "/tmp/agent.pcm" ) )
```

### 现场音频—— `channel.createWriteStream`

对称对应到 `createReadStream`返回节点 `Writable` 将活音注入频道外出行走的腿上——管子放入TTS流中,活口翻译入音,一瓶子合成出的声音,任何产生PCM的东西.

```js
const writer = channel.createWriteStream( {
  format:      "l16",   // v1: l16 only
  samplerate:  8000,    // v1: 8000 only
  numchannels: 1        // v1: mono only
} )

writer.format        // "l16"
writer.samplerate    // 8000
writer.numchannels   // 1
writer.writerId      // monotonic id

writer.write( pcmBuffer )   // accepts any chunk size — framed internally
writer.end()                 // flushes the tail then reverts to silence
writer.destroy()             // immediate teardown, discards buffered samples

ttsStream.pipe( writer )     // standard Node stream composition
```

**与 `play`**

一个作家和 `channel.play` 共享频道上的单个出源槽。 开始一个写入器取代任何活动播放器( emits) `play/end reason=new`页:1 `channel.play` 取代活动作者。 最多有一个外出源;当两者都不在场时,信道发出沉默.

**结构**

你们可以 `.write` 任意块大小 —— Rust 侧缓冲器会用字节来框起它们,为勾选设置了20ms的插槽. 8 kHz L16 流需要 ~ 16,000 字节/秒( 每 20 ms 帧 有 320 字节) , 因此是典型的 `.pipe` 从一个WebSocket或HTTP身体保持舒适.

**后压**

Rust-side缓冲器以1s(50×20ms)为界. 如果消费者写得比滴水管快, `_write` 将其召回延后到空格空出——标准节点 `Writable` 后压踢入并 `.write` 返回时 `false`。在下行中(没有写入一个勾选符),该频道为该槽发出静音.

**期末**

`writer.end()` 放下JS的发件人 鲁斯特 `AudioWriter` 看到关闭,冲出任何部分框架 加上沉默,然后从频道退休。 A 类 `play/end reason=completed` 事件起火——与基于文件的对称 `play` 自然结束.

**例子——将 TTS 响应输入活调:**

```js
const writer = channel.createWriteStream()

const res = await fetch( "https://tts.example.com/say", {
  method: "POST",
  body:   JSON.stringify( { text: "Your call is important to us." } ),
} )
// res.body is a Readable web stream of raw PCM-16 @ 8 kHz mono.
// Pipe straight through; backpressure is preserved end-to-end.
res.body.pipe( writer )
```

## 用户

### 调音器生成

为了让RTP尽可能可扩展,我们不会支持飞音生成. 目前磁盘空间比CPU资源便宜得多. 在8K取样的1S瓦夫数据为16K. 使用声音,我们可以为每个支持的可解码器提供wav文件,并方便地循环,这需要极少的CPU上浮.

我们需要提供的是生成 wav 文件的有用工具, 生成用于电信(即振铃、 DTMF等) 的音量.

```js

const prtp = require( "@babblevoice/projectrtp" ).projectrtp

let filename = "/some/file.wav"
prtp.tone.generate( "350+440*0.5:1000", filename )

```

格式试图密切遵循格式 [https://www.itu.int/dms pub/itu-t/opb/sp/T-SP-E.180-2010-PDF-E.pdf 互联网档案馆的存檔,存档日期2014-12-21](https://www.itu.int/dms_pub/itu-t/opb/sp/T-SP-E.180-2010-PDF-E.pdf) - 虽然该标准在某些方面不是最明确的.

我们目前支持

-   \+ 共增加1个或更多频率
-   '\*' 减小振幅( 即能力乘以此值, 0. 75 是 0. 75 x 最大值)
-   ':"结肠后值为cadences,即调子移动到下个调子前的持续时间
-   '~' start~ end, 例如, 这可以用于频率或振幅, 350+440\* 0.5~0: 100 将产生从 anp 0. 5 到 0 到 1000 mS 期间的音调

实例

#### 英国拨号:

```js
prtp.tone.generate( "350+440*0.5:1000" "dialtone.wav" )
```

#### 联合王国

```js
prtp.tone.generate( "400+450*0.5/0/400+450*0.5/0:400/200/400/2000" "ringing.wav" )
```

#### 自动取款机

|  | 1209赫兹 | 1336赫兹 | 1477赫兹 | 1633Hz (英语) |
| --- | --- | --- | --- | --- |
| 697赫兹 | 1个 | 2个 | 3个 | A 类 |
| 770赫兹 | 页:1 | 页:1 | 6个 | 页:1 |
| 852赫兹 | 第7条 | 第8条 | 第9条 | C级 |
| 941赫兹 | \* 联合国 | 0 个 | {\\fn方正粗倩简体\\fs12\\an8\\1cHFFFF00\\b0} | D级 |

例1将混合1209Hz和697Hz

```js
prtp.tone.generate( "697+1209*0.5:400" "dtmf1.wav" )
prtp.tone.generate( "697+1209*0.5/0/697+1336*0.5/0/697+1477*0.5/0:400/100", "dtmf1-3.wav" )
```

### 开始

-   Wav文件类型(l16, rate pcmu, pcma等)之间的格式转换.
-   犯罪时保持平整(在CI中强制):

```
cd rust && cargo clippy --all-targets -- -D warnings
```

# 参考文献

-   [RFC 3550 - RTP:实时应用运输协议](https://www.rfc-editor.org/rfc/rfc3550)
-   [RFC 3711 - 《安全实时运输议定书》](https://www.rfc-editor.org/rfc/rfc3711)
-   [RFC 5763 - 建立安全实时运输协议(SRTP)的框架 使用数据gram运输层安全的安全环境(DTLS)](https://www.rfc-editor.org/rfc/rfc5763)
-   [RFC 5764 - 数据gram 运输层安全(DTLS)扩展以建立安全实时运输协议(SRTP)的密钥](https://www.rfc-editor.org/rfc/rfc5764)
-   [RFC 8842 - 会话描述协议(SDP) 数据克传输层安全(DTLS)和运输层安全(TLS)的提供/答复考虑](https://www.rfc-editor.org/rfc/rfc8842)

## 常见问题

### @babblevoice/projectrtp 是什么？

可缩放节点添加 RTP 服务器

### 如何安装 @babblevoice/projectrtp？

在项目目录运行 npm install @babblevoice/projectrtp，或使用 pnpm add / yarn add / bun add。

### @babblevoice/projectrtp 支持 TypeScript 吗？

该包的 package\.json 没有声明类型入口。需要类型提示时，可以在 npm 上查找社区维护的 @types/babblevoice\_\_projectrtp 是否存在。

### @babblevoice/projectrtp 支持 ESM 还是 CommonJS？

以 CommonJS 形式发布，可以直接 require\(\)；在 ES Module 项目中也可以用 import 引入（Node\.js 会把 module\.exports 作为默认导出）。

### @babblevoice/projectrtp 可以商用吗？

@babblevoice/projectrtp 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @babblevoice/projectrtp 的下载量有多少？

根据 npm 官方下载统计，@babblevoice/projectrtp 在 2026/10/08 – 2026/11/06 这 30 天内被下载 1,934 次，日均约 64 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @babblevoice/projectrtp 还在维护吗？

最新版本 3\.7\.0 发布于 2026/08/12（2 个月前）；至今共发布 88 个版本，其中过去 12 个月发布了 35 个；首次发布于 2022/06/17。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

