12 KiB
서버 방향성
이 문서는 macOS, Ubuntu, Rocky Linux 9, Windows WSL2에서 실행할 수신기/믹서 서버의 초기 방향을 정리합니다.
현재 단계의 목표는 복잡한 믹서 기능을 만드는 것이 아니라, Orange Pi Zero 2W 클라이언트에서 보낸 오디오가 서버 실행 장비에서 실제로 들리는 최소 경로를 확인하고, 이후 2대에서 16대까지 확장할 수 있는 기반을 잡는 것입니다.
Orange Pi Zero 2W 클라이언트 -> UDP/Wi-Fi -> 서버 -> 기본 오디오 출력
역할
서버는 수신 장비에서 실행되며 다음 역할을 맡습니다.
- 고정 UDP 포트에서 클라이언트의 오디오 패킷을 수신합니다.
- 수신 패킷의 순서와 기본 메타데이터를 확인합니다.
- PCM 오디오 payload를 실행 OS의 오디오 출력 장치로 재생합니다.
- 첫 bring-up에서는 송신기 1대로 오디오 경로를 확인합니다.
- 실제 목표 규모는 최소 2대, 최대 16대 송신기입니다.
- 이후 단계에서 2대 이상의 다중 송신기 믹싱, 동기화, UI를 확장 후보로 검토합니다.
초기 범위
초기 서버의 성공 기준은 다음과 같습니다.
- 지원 OS에서 서버 프로그램을 실행할 수 있습니다.
- 서버가 지정된 UDP 포트에 바인딩됩니다.
- Orange Pi Zero 2W 클라이언트가 보낸 UDP 패킷을 수신합니다.
- 수신한 PCM 프레임을 실행 OS의 기본 오디오 출력으로 재생합니다.
- 패킷 수신 상태, sequence 변화, 간단한 손실 통계를 확인할 수 있습니다.
다중 송신기 믹싱은 1대 오디오 경로 확인 이후의 핵심 확장 목표입니다. 송신기별 음량 조절, 자동 검색, 압축 코덱, 지터 버퍼 고도화, GUI는 초기 성공 이후에 다룹니다.
목표 송신기 규모
현재 목표 규모는 다음과 같습니다.
minimum_senders = 2
maximum_senders = 16
첫 구현과 첫 실기 검증은 문제 원인을 줄이기 위해 송신기 1대로 시작합니다. 이후 검증은 2대, 4대, 8대, 16대 순서로 늘리는 방향을 우선합니다.
현재 무압축 PCM_S16LE / mono / 48 kHz / 10 ms 기준으로 송신기 1대는 UDP/IP 포함 대략 0.8 Mbps 이상을 사용합니다. 16대는 단순 계산으로 13 Mbps 이상입니다. 권장 네트워크는 2.4 GHz Wi-Fi로 두되, 실제 2.4 GHz 환경에서는 MAC 오버헤드, 주변 간섭, 재전송, airtime 경쟁, 공유기 성능 때문에 단순 대역폭 계산보다 훨씬 보수적으로 검증해야 합니다.
따라서 16대 목표를 달성하려면 단순 대역폭보다 다음 항목을 중요하게 봅니다.
- 2.4 GHz Wi-Fi 기준 검증
- 송신기별 sequence 손실과 순서 역전 통계 확인
- 송신기 수 증가에 따른 지터 버퍼 underflow와 overflow 관찰
- 10 ms 프레임 유지가 어려울 경우 20 ms 프레임 후보 검토
- 16대 검증 전 압축 코덱 도입 여부 재검토
네트워크 수신 방향
초기 수신은 UDP 기반으로 진행합니다.
포트는 다음 값을 초기 후보로 둡니다.
listen_port = 4860
서버는 먼저 단일 클라이언트의 패킷만 받아 오디오 경로를 확인합니다. 이후 같은 포트로 들어오는 여러 클라이언트를 sender_id, session_id, sequence, capture_sample_index로 구분해 최소 2대, 최대 16대까지 단계적으로 검증합니다.
포트 운영 방향
초기 기본값은 서버 UDP 수신 포트 1개입니다.
마이크가 여러 대가 되더라도 먼저 하나의 UDP 포트로 받고, 패킷 헤더의 송신기 식별자와 sequence, timestamp를 이용해 서버 내부에서 스트림을 나누는 방향을 우선합니다.
포트를 하나만 쓰는 이유는 다음과 같습니다.
- OS 방화벽과 공유기 설정이 단순합니다.
- 송신기 수가 늘어나도 서버 실행 옵션이 복잡해지지 않습니다.
- 자동 검색을 추가할 때 안내할 수신 포트가 하나라 단순합니다.
- 서버가 송신기별 지터 버퍼와 믹싱 상태를 한 곳에서 관리하기 쉽습니다.
마이크 수만큼 포트를 나누는 방식은 다음 상황에서만 후보로 둡니다.
- 송신기마다 별도 서버 프로세스를 띄워 완전히 분리해 테스트해야 할 때
- 특정 네트워크 도구로 송신기별 트래픽을 강하게 분리해서 봐야 할 때
- 나중에 운영상 포트 분리가 더 명확하다고 판단될 때
따라서 현재 방향은 listen_port = 4860 하나를 사용하고, 다중 송신기는 패킷 메타데이터로 구분하는 것입니다.
개발 도구와 의존성 방향
서버는 장기적으로 macOS, Ubuntu, Rocky Linux 9, Windows WSL2에서 실행할 수 있게 설계합니다.
Homebrew를 개발/실행 준비 기준으로 둡니다. macOS와 Linux 개발 환경에서 같은 방식으로 CMake와 miniaudio 같은 의존성을 설치할 수 있고, Windows는 네이티브 Windows가 아니라 WSL2 Linux 환경을 사용합니다.
서버 구현 기준은 다음 방향을 우선합니다.
- 빌드: CMake
- 의존성 관리: Homebrew
- Windows 지원: WSL2 Linux 환경
- 네이티브 Windows 빌드: 초기 범위에서 제외
WSL2에서 실제 오디오를 출력하려면 WSLg 또는 Linux 오디오 출력 경로가 동작해야 합니다. Windows 네이티브 오디오 API 지원은 초기 범위에 포함하지 않습니다.
공식 참고 링크:
오디오 출력 방향
초기 오디오 출력은 여러 OS에서 C++로 접근 가능한 라이브러리를 후보로 검토합니다.
후보는 다음과 같습니다.
- miniaudio: 단일 파일에 가까운 경량 오디오 라이브러리입니다. macOS와 Linux의 기본 오디오 백엔드를 지원하고 Homebrew로 설치할 수 있어 초기 우선 후보로 둡니다.
- Core Audio: macOS 기본 오디오 API입니다. 추가 런타임 의존성이 적지만 초기 구현이 다소 길어질 수 있습니다.
- PortAudio: 크로스 플랫폼 오디오 입출력 라이브러리입니다. 예제가 많고 초기 재생 경로를 빠르게 만들 수 있습니다.
- RtAudio: C++ 인터페이스가 단순한 오디오 입출력 라이브러리입니다.
첫 구현에서는 안정적인 최소 재생 경로를 우선합니다. 현재 우선 후보는 miniaudio입니다.
초기 오디오 포맷 후보
클라이언트 방향성과 맞춰 초기 포맷 후보는 다음과 같습니다.
sample_rate = 48000
sample_format = signed 16-bit little endian
channels = 1
frame_ms = 10
48 kHz / 16-bit / mono / 10 ms 기준 payload는 960바이트입니다. UDP/IP 헤더를 더해도 일반적인 MTU 1500 안에 들어가므로, 20 ms 프레임보다 UDP fragmentation 위험이 낮습니다.
이 값은 시작점입니다. 실제 USB 마이크나 출력 경로에서 다른 포맷이 더 자연스러우면 구현 전에 조정합니다.
패킷 포맷 후보
초기 패킷은 서버가 지정하는 고정 길이 헤더와 PCM payload로 구성하는 방향을 검토합니다.
헤더 v1 후보:
magic u32 "MIC1"
version u8 1
header_len u8 56
packet_type u8 1 = audio
flags u8 reserved
sender_id u16 0 reserved, 1..65535
stream_id u16 initial 0
session_id u32 random value after sender restart
sequence u32 increments per sender/session
capture_sample_index u64 first sample index in this packet
sender_monotonic_us u64 sender monotonic timestamp
sample_rate u32 initial 48000
frame_samples u16 initial 480
payload_bytes u16 initial 960
codec_id u8 1 = PCM_S16LE
sample_format u8 1 = S16LE
channels u8 initial 1
channel_layout u8 0 = mono/default
header_crc32 u32 0 allowed in initial implementation
reserved u32 future use
헤더는 네트워크 바이트 오더를 사용합니다. PCM payload는 초기 후보인 PCM_S16LE에 맞춰 little endian으로 둡니다.
서버는 sender_id, session_id, sequence, capture_sample_index를 이용해 송신기 구분, 재시작 감지, 패킷 손실, 순서 역전, 재생 위치를 확인할 수 있어야 합니다. 초기 단계에서는 복잡한 재전송이나 복구를 넣지 않고, 끊김 여부를 관찰하는 데 집중합니다.
지터와 버퍼링 방향
Wi-Fi UDP 오디오에서는 패킷 도착 간격이 흔들릴 수 있습니다.
초기 버전은 아주 단순한 짧은 재생 버퍼를 후보로 둡니다.
- 너무 짧으면 끊김이 늘어납니다.
- 너무 길면 지연이 커집니다.
- 첫 목표는 지연 시간 최적화가 아니라 소리 경로 확인입니다.
구체적인 버퍼 길이는 구현 전 테스트 환경과 오디오 라이브러리 선택에 맞춰 정합니다.
설정 방향
초기 서버 설정 후보는 다음과 같습니다.
listen_port = 4860
web_port = 4861
sample_rate = 48000
channels = 1
frame_ms = 10
audio_output = default
송신기별 음량 조절 설정은 현재 범위에서 제외합니다. 초기 목표는 수신한 단일 송신기 오디오를 노트북 스피커로 출력하는 것이고, 다음 목표는 2대 이상 송신기의 동시 수신과 믹싱입니다.
설정 파일 형식은 단순 key-value 텍스트 형식을 후보로 둡니다. 자동 검색을 추가하더라도 고정 포트와 고정 설정 방식은 유지합니다.
Web UI 방향
서버 제어와 상태 확인은 GUI 앱보다 Web UI를 우선합니다.
현재 기준은 다음과 같습니다.
web_host = 127.0.0.1
web_port = 4861
Web UI는 같은 장비의 브라우저에서만 접근하는 localhost 전용으로 둡니다. 같은 Wi-Fi의 다른 장비에서 접속하는 기능은 현재 범위에 포함하지 않습니다. 별도 비밀번호나 인증은 두지 않고, 127.0.0.1 바인딩으로 외부 노출을 막습니다.
초기 Web UI는 다음 기능을 제공합니다.
- UDP 수신 상태와 오류 표시
- 오디오 출력 상태와 오류 표시
- sender별 packet, dropped, out_of_order, last seen 표시
- 전체 output mute
- sender별 mute
- sender별 gain
- sender별 display name
- 통계 reset
UDP 바인딩 실패나 수신 오류가 발생하면 Web UI의 udp_state, udp_error에 표시하는 방향을 우선합니다.
검증 순서
초기 검증은 다음 순서를 따릅니다.
- 지원 OS에서 서버가 UDP 포트를 열 수 있는지 확인합니다.
- 같은 장비 또는 다른 장비에서 테스트 UDP 패킷이 수신되는지 확인합니다.
- Orange Pi Zero 2W와 서버 실행 장비 사이의 Wi-Fi 통신을 확인합니다.
- 클라이언트 1대의 오디오 패킷이 서버에 도착하는지 확인합니다.
- 서버가 수신한 단일 송신기 PCM 프레임을 실행 OS의 오디오 출력으로 재생합니다.
- sequence 로그로 패킷 손실과 순서 역전을 관찰합니다.
- 송신기를 2대, 4대, 8대, 16대 순서로 늘리며 손실, 순서 역전, 지터 버퍼 underflow와 overflow를 기록합니다.
- 실제 소리 끊김과 지연을 기록합니다.
현재 구현 단계
서버 구현은 Homebrew, CMake, miniaudio 기준으로 시작합니다.
현재 서버 구현 범위는 다음과 같습니다.
- UDP
4860바인딩 - localhost Web UI
127.0.0.1:4861 - 서버 지정 56바이트 패킷 헤더 v1 파싱
- 단일 활성
sender_id의PCM_S16LE / mono / 48 kHz / 10 mspayload 재생 - sequence 기반 손실/순서 역전 로그 출력
- Web UI를 통한 output mute, sender mute, sender gain, sender display name, 통계 reset
다음 작업은 클라이언트 송신 패킷을 서버 지정 헤더 v1에 맞추고, 실제 송신기에서 들어온 오디오가 실행 OS의 기본 출력 장치로 재생되는지 확인하는 것입니다. 그 다음 서버 작업은 단일 활성 송신기 제한을 풀고, 2대에서 16대까지 송신기별 버퍼와 믹싱을 검증하는 방향으로 진행합니다.