VOIP 通话 + 重采样 + PHP

发布: (2026年1月4日 GMT+8 12:17)
3 min read
原文: Dev.to

Source: Dev.to

概览

本指南演示如何使用 Swoole 在 PHP 中实现实时 VoIP 通话,音频采样率为 48 kHz。SpechPhone 项目提供了一个在浏览器中运行的软电话,它在后端完成 SIP/RTP 处理,并通过 WebSocket 将 PCM 音频传递给浏览器,无需依赖 Asterisk/AGI。

架构

  • middleware.php – 提供 UI 并控制通话的 HTTP/WebSocket 服务器。
  • audio.php – 负责混音并流式发送音频包的音频服务器。

媒体流的工作流程如下:

  1. 后端接收 RTP 包。
  2. libspech 库使用 pcg729 运行时解码这些包。
  3. 解码后的音频以 PCM 块的形式发送到 WebSocket 客户端,浏览器使用 AudioContext 播放。

实现实时性能的关键是使用 Swoole 协程,它们允许在不阻塞主进程的情况下同时处理多个通话。

前置条件与安装

# 系统依赖
sudo apt update && sudo apt install -y openssl

# 克隆仓库
git clone https://github.com/spechshop/spechphone && cd spechphone
git clone https://github.com/spechshop/libspech

# 优化的 PHP 运行时 (pcg729)
curl -L https://github.com/spechshop/pcg729/releases/download/current/php -o php
chmod +x ./php
sudo cp php /usr/local/bin/php

在不同的终端中启动两个服务:

php middleware.php
php audio.php

重要: 项目使用 Swoole 扩展(而非 OpenSwoole)。

Opus / 48 kHz 编解码器提供

trunkController 可以通过 SDP 提供不同的编解码器。要使用 48 kHz 的 Opus:

$phone->mountLineCodecSDP('opus/48000/2');

这会使 RTP 流协商为 48 kHz,从而实现高质量音频。

完整的 PHP 示例

register(2)) {
        throw new \Exception('Falha no registro');
    }

    // Oferecer codec Opus em SDP (48 kHz)
    $phone->mountLineCodecSDP('opus/48000/2');

    $phone->onRinging(function ($phone) {
        echo "Tocando...\n";
    });

    $phone->onAnswer(function (trunkController $phone) {
        echo "Atendido. Recebendo mídia...\n";
        $phone->receiveMedia();
        \Swoole\Coroutine::sleep(10);
    });

    $phone->onReceiveAudio(function ($pcmData, $peer, trunkController $phone) {
        echo "Recebido: " . strlen($pcmData) . " bytes\n";
    });

    $phone->onHangup(function (trunkController $phone) {
        echo "Chamada finalizada\n";
        $phone->close();
    });

    $phone->call('5511999999999');
});

示例已记录于:

建议的实验

1. 更换提供的编解码器

将编解码器提供行改为 L16/8000,并比较 onReceiveAudio 中收到的字节量。

$phone->mountLineCodecSDP('L16/8000');

2. 对 PCM 流进行仪表化

记录每个收到的 PCM 块的大小(strlen),观察大小、频率和抖动的模式。

3. 更新 UI

实现一个通过 WebSocket 的 “thin” 客户端,响应 ringingansweredhangup 事件,并在页面上显示简短的提示信息。

主要链接

  • SpechPhone(仓库)
  • SpechPhone README(volume-dev 分支)
  • libspech(仓库)
  • libspech README(spech 分支)
  • libspech example.php
  • pcg729 运行时发布
Back to Blog

相关文章

阅读更多 »

使用 DataBlock 探索真实世界 API

比较 Symfony 和 Laravel 使用 GitHub 与 Packagist 数据 在第一篇文章《Handling Nested PHP Arrays Using DataBlock》中,我们探索了 DataBlock 与一个 s...