VOIP 통화 + 리샘플 + PHP

발행: (2026년 1월 4일 오후 01:17 GMT+9)
4 분 소요
원문: Dev.to

Source: Dev.to

개요

이 가이드는 Swoole을 사용하여 PHP에서 48 kHz 오디오를 실시간으로 전송하는 VoIP 통화를 구현하는 방법을 보여줍니다. 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를 통해 다양한 코덱을 제안할 수 있습니다. Opus를 48 kHz로 사용하려면 다음과 같이 설정합니다:

$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 업데이트

ringing, answered, hangup 이벤트에 반응하여 화면에 간단한 메시지를 표시하는 “thin” WebSocket 클라이언트를 구현합니다.

주요 링크

  • SpechPhone (repo)
  • SpechPhone README (branch volume-dev)
  • libspech (repo)
  • libspech README (branch spech)
  • libspech example.php
  • pcg729 runtime release
Back to Blog

관련 글

더 보기 »

1390. 네 개의 약수

문제 설명: 정수 배열 nums가 주어지면, 해당 배열에서 정확히 네 개의 약수를 갖는 정수들의 약수 합을 반환한다. 그런 수가 없으면...

🔥 PHPS 최악 디버그 악몽… 폐위! 🔥

PHP 개발자 여러분: 현실을 직시합시다 — 디버깅이 정말 힘들었습니다. Xdebug의 불안정함, IDE 리스너 설정, Docker 네트워킹, 그리고 끝없는 dd 호출 사이에서 우리는 많은 시간을 보냈습니다. ...