Hlasové hovory — specifikace (budoucí fáze)¶
Přehled¶
Peer-to-peer hlasová komunikace integrovaná do ChatWindow. Hovor je iniciován tlačítkem 🎙 ve vstupní liště ConversationPanel — prozatím disabled. Backend signalizace přes existující FastAPI WebSocket.
Architektura¶
Volající Backend (FastAPI WS) Přijímající
│ │ │
│── /ws/voice/call ───────►│ │
│ {conv_id, offer_sdp} │── push: incoming_call ───────►│
│ │ {conv_id, caller, sdp} │
│◄─ answer_sdp ────────────│◄── answer ────────────────────│
│ │ {conv_id, sdp} │
│── ICE candidates ────────►│◄── ICE candidates ────────────│
│◄─────────────────────────│──────────────────────────────►│
│ │ │
│ ← přímý RTP proud (P2P nebo přes TURN) → │
Komponenty¶
| Komponenta | Tech | Umístění |
|---|---|---|
| Signalizace | FastAPI WebSocket | backend/app/routers/voice.py |
| Audio capture/playback | sounddevice |
launcher voice_call.py |
| Kódování | Opus via opuslib |
launcher voice_call.py |
| ICE/STUN | veřejný STUN (stun.l.google.com:19302) | launcher |
| TURN fallback | vlastní coturn na vm-gateway | infrastructure/ |
| SDP exchange | přes WS signalizaci |
Backend — nové endpointy¶
WS /ws/voice/{conv_id} — signalizace (offer/answer/ICE/hangup)
POST /voice/call — zahájení hovoru (notifikace ostatním)
POST /voice/hangup — ukončení
GET /voice/status/{conv_id} — aktivní hovor v konverzaci?
WebSocket zprávy¶
// offer (volající → backend → přijímající)
{"type": "offer", "sdp": "...", "caller_id": "uuid"}
// answer (přijímající → backend → volající)
{"type": "answer", "sdp": "..."}
// ICE candidate (oba směry)
{"type": "ice", "candidate": {"candidate": "...", "sdpMid": "0"}}
// hangup
{"type": "hangup"}
// incoming_call (push od backendu)
{"type": "incoming_call", "conv_id": "...", "caller_name": "..."}
Launcher — nové soubory¶
voice_call.py¶
class VoiceCall:
def __init__(self, session, conv_id, ws_url):
...
def start_call(self): # inicializace sounddevice + WebSocket
def answer_call(self, sdp): # přijmout příchozí hovor
def send_audio(self): # vlákno: capture mic → Opus → send
def recv_audio(self): # vlákno: recv → Opus decode → playback
def hangup(self): # ukončit hovor, zavřít WS
voice_ui.py¶
IncomingCallDialog— popup "Příchozí hovor od X" s Přijmout/OdmítnoutActiveCallBar— lišta v ConversationPanel (mute, hangup, duration timer)
ChatWindow — integrace¶
ConversationPanel._voice_btn(🎙) →VoiceCall.start_call()chat_poll.pynebo samostatný WS listener →IncomingCallDialogActiveCallBarse zobrazí nad vstupní lištou po dobu trvání hovoru
Nastavení zařízení¶
Výběr mikrofonu a reproduktorů je již implementován v Nastavení → Zvuk:
- settings.get("audio_input") → název zařízení pro sounddevice.InputStream
- settings.get("audio_output") → název zařízení pro sounddevice.OutputStream
- settings.get("audio_volume") → hlasitost 0–100
Závislosti (přidat do requirements.txt)¶
sounddevice>=0.4.6
opuslib>=3.0.1 # Opus codec (vyžaduje libopus.dll na Windows)
websockets>=12.0 # pro WS voice spojení
Windows: libopus.dll¶
Opus není součástí Windows. Nutný postup:
1. Stáhnout opus.dll z libopus.org (precompiled) nebo vcpkg
2. Přidat do dist/ adresáře vedle .exe
3. PyInstaller spec: přidat ('opus.dll', '.') do datas
Priorita a scope¶
- Fáze: V (po F4 Chat a F5 Support)
- Rozsah MVP: 1:1 hovory v DM konverzacích, skupinové hovory mimo scope MVP
- Šifrování: SRTP (vestavěno v libopus přes WebRTC) nebo TLS transport
- Nahrávání: mimo scope (GDPR komplikace)
- Video: mimo scope
Odhadovaný rozsah implementace¶
| Část | Odhad |
|---|---|
| Backend WS signalizace | ~200 řádků |
voice_call.py audio engine |
~300 řádků |
voice_ui.py dialogy |
~150 řádků |
| Integrace do ChatWindow | ~80 řádků |
| TURN server konfigurace | ~50 řádků konfigurace |
| Celkem | ~780 řádků |