VOIP 통화 + 리샘플 + PHP

발행: (2026년 1월 4일 오후 01:17 GMT+9)
4 min read
원문: 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

관련 글

더 보기 »

DataBlock와 실제 API 탐색

GitHub와 Packagist 데이터를 사용하여 Symfony와 Laravel을 비교합니다. 첫 번째 기사 “Handling Nested PHP Arrays Using DataBlock”에서 우리는 DataBlock을 …