今日は理屈より「動いてること」が一番伝わる日なので、実際に動かしたデモを載せます。
(12/15〜12/23でまとめたMVP仕様・実装位置の通り、SIP/RTP/録音配信までが対象です)
デモ
- 事前にwhisper/ollama/voicevoxを立ち上げておく
- Zoiper(または任意のSIPフォン)から発信
- INVITE → 200 OK → ACK で通話確立
- ずんだもんの固定音声->質問->whisperが音声認識->ollamaに認識した内容を質問、応答した内容をvoicevoxで音声合成->zoiper側に返す
- RTP(PCMU/8000)受信 →
mixed.wavに録音 - 通話終了(BYE)→
/recordings/.../mixed.wavに出力
このデモで確認するMVP要件(12/15再掲)
- SIP:INVITE → 200 OK → ACK が通る / BYEに200を返す
- RTP:PCMU/8000固定で受信し、録音(mixed.wav+meta.json)を生成できる
- 録音:
/recordings/<callId>/mixed.wavがちゃんととれているかを確認する
実行手順(ざっくり・最短)
1) 環境変数(例)
最低限、SIPと録音配信周りが分かればOKです。
-
SIP_BIND_IP/SIP_PORT -
ADVERTISED_IP/ADVERTISED_RTP_PORT -
RECORDING_HTTP_ADDR(例:0.0.0.0:18080) -
RECORDING_BASE_URL(未指定ならRECORDING_HTTP_ADDRを http:// で利用) -
INGEST_CALL_URL(使う場合のみ)
2) サーバ起動
- 事前にwhisper/ollama/voicevoxを立ち上げておく
cargo run
3) Zoiperで発信
- 発信先:
sip:<任意>@<サーバIP>:<SIP_PORT> - ここで通話が確立し、RTPが流れてくればOK
録音の確認
通話後に以下が生成されていれば “音は取れてる” 判定です。
storage/recordings/<timestamp_callid>/mixed.wavstorage/recordings/<timestamp_callid>/meta.json
が再生できれば、録音配信もOKです。
結果
できました
msuda@msuda-System-Product-Name:~/workspace/virtual_voicebot_4/virtual_voicebot/virtual-voicebot-backend$ SIP_BIND_IP=0.0.0.0 SIP_PORT=5060 RTP_PORT=10000 LOCAL_IP=192.168.10.110 ADVERTISED_IP=192.168.10.110 RECORDING_HTTP_ADDR=0.0.0.0:18080 RUST_LOG=info ./run_uas.sh
[run_uas] SIP UDP/TCP 0.0.0.0:5060 (advertised 192.168.10.110)
[run_uas] RTP 10000
[run_uas] Recording 0.0.0.0:18080
[run_uas] RUST_LOG info
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.13s
Running `target/debug/virtual-voicebot-backend`
2025-12-21T08:27:47.265Z INFO virtual_voicebot_backend Listening SIP UDP on 0.0.0.0:5060, SIP TCP on 0.0.0.0:5060, RTP on 0.0.0.0:10000
2025-12-21T08:27:47.265Z INFO virtual_voicebot_backend [recording] static HTTP on 0.0.0.0:18080
2025-12-21T08:27:47.266Z INFO virtual_voicebot_backend::http [http] serving recordings on 0.0.0.0:18080
2025-12-21T08:27:47.266Z INFO virtual_voicebot_backend::transport::packet [packet] RTP socket bound on port 10000
2025-12-21T08:27:47.266Z INFO virtual_voicebot_backend::transport::packet [packet] SIP TCP listener bound on 0.0.0.0:5060
2025-12-21T08:27:48.857Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:27:52.856Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:28:25.416Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:28:25.416Z WARN virtual_voicebot_backend [main] TransactionTimeout for call_id=JXyY55Zf_z5rC5Y4FnwLMw..
2025-12-21T08:28:25.916Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:28:26.915Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:28:28.915Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:28:29.917Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=1021
2025-12-21T08:28:29.917Z INFO virtual_voicebot_backend::sip [sip invite sdp] call_id=L1YYryKrtpk6KLm-js9aPg.. sdp=v=0\no=Z 0 1619016 IN IP4 192.168.10.110\ns=Z\nc=IN IP4 192.168.10.110\nt=0 0\nm=audio 41352 RTP/AVP 106 9 98 101 0 8 3\na=rtpmap:106 opus/48000/2\na=fmtp:106 sprop-maxcapturerate=16000; minptime=20; useinbandfec=1\na=rtpmap:98 telephone-event/48000\na=fmtp:98 0-16\na=rtpmap:101 telephone-event/8000\na=fmtp:101 0-16\na=sendrecv\na=rtcp-mux\n
2025-12-21T08:28:29.917Z INFO virtual_voicebot_backend [main] new INVITE, call_id=L1YYryKrtpk6KLm-js9aPg..
2025-12-21T08:28:29.917Z INFO virtual_voicebot_backend::sip [sip ->] 192.168.10.110:5060 -> Udp(192.168.10.110:5061) SIP/2.0 100 Trying
2025-12-21T08:28:29.918Z INFO virtual_voicebot_backend::transport::packet [sip ->] 0.0.0.0:5060 -> 192.168.10.110:5061 len=277
2025-12-21T08:28:29.918Z INFO virtual_voicebot_backend::sip [sip ->] 192.168.10.110:5060 -> Udp(192.168.10.110:5061) SIP/2.0 180 Ringing
2025-12-21T08:28:29.918Z INFO virtual_voicebot_backend::transport::packet [sip ->] 0.0.0.0:5060 -> 192.168.10.110:5061 len=278
2025-12-21T08:28:29.918Z INFO virtual_voicebot_backend::sip [sip 200 sdp] call_id=L1YYryKrtpk6KLm-js9aPg.. sdp=v=0\no=rustbot 1 1 IN IP4 192.168.10.110\ns=Rust PCMU Bot\nc=IN IP4 192.168.10.110\nt=0 0\nm=audio 10000 RTP/AVP 0\na=rtpmap:0 PCMU/8000\na=sendrecv\n
2025-12-21T08:28:29.918Z INFO virtual_voicebot_backend::sip [sip ->] 192.168.10.110:5060 -> Udp(192.168.10.110:5061) SIP/2.0 200 OK
2025-12-21T08:28:29.918Z INFO virtual_voicebot_backend::transport::packet [sip ->] 0.0.0.0:5060 -> 192.168.10.110:5061 len=498
2025-12-21T08:28:29.931Z WARN virtual_voicebot_backend::rtp::rx [rtp recv] unsupported payload type 95 from 192.168.10.110:41352 (call_id=L1YYryKrtpk6KLm-js9aPg..)
2025-12-21T08:28:30.032Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=410
2025-12-21T08:28:30.032Z INFO virtual_voicebot_backend [main] ACK for call_id=L1YYryKrtpk6KLm-js9aPg..
2025-12-21T08:28:30.049Z INFO virtual_voicebot_backend::session::session [rtp tx] sending 287 frames (45920 samples) to 192.168.10.110:41352
2025-12-21T08:28:32.916Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:28:36.084Z INFO virtual_voicebot_backend::session::session [session L1YYryKrtpk6KLm-js9aPg..] sent intro wav /home/msuda/workspace/virtual_voicebot_4/virtual_voicebot/virtual-voicebot-backend/test/simpletest/audio/zundamon_intro.wav
2025-12-21T08:28:36.084Z INFO virtual_voicebot_backend::session::session [session L1YYryKrtpk6KLm-js9aPg..] capture window started after intro playback
2025-12-21T08:28:36.917Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:28:40.916Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:28:44.916Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:28:46.112Z INFO virtual_voicebot_backend::session::session [session L1YYryKrtpk6KLm-js9aPg..] buffered audio ready for app (126080 bytes)
2025-12-21T08:28:46.315Z INFO virtual_voicebot_backend::ai User question (whisper): こんにちは
2025-12-21T08:28:46.316Z INFO virtual_voicebot_backend::ai User question (whisper): User: こんにちは
2025-12-21T08:28:46.359Z ERROR virtual_voicebot_backend::ai call_gemini failed: GEMINI_API_KEY must be set, falling back to ollama
2025-12-21T08:28:48.648Z INFO virtual_voicebot_backend::ai Ollama status: 200 OK
2025-12-21T08:28:48.648Z INFO virtual_voicebot_backend::ai Ollama raw body: {"model":"gemma3:4b","created_at":"2025-12-21T08:28:48.647630736Z","message":{"role":"assistant","content":"承知いたしました。ご挨拶ありがとうございます!何かお手伝いできることはありますか?\n"},"done":true,"done_reason":"stop","total_duration":2246959067,"load_duration":2078113704,"prompt_eval_count":25,"prompt_eval_duration":13748313,"eval_count":19,"eval_duration":116971086}
2025-12-21T08:28:48.649Z INFO virtual_voicebot_backend::ai LLM answer (ollama fallback): 承知いたしました。ご挨拶ありがとうございます!何かお手伝いできることはありますか?
2025-12-21T08:28:48.916Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:28:50.076Z INFO virtual_voicebot_backend::ai Zundamon TTS written to /tmp/tts_output.wav
2025-12-21T08:28:50.100Z INFO virtual_voicebot_backend::session::session [rtp tx] sending 355 frames (56800 samples) to 192.168.10.110:41352
2025-12-21T08:28:52.917Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:28:56.917Z INFO virtual_voicebot_backend::transport::packet [sip <-] 192.168.10.110:5061 -> 0.0.0.0:5060 len=708
2025-12-21T08:28:59.319Z INFO virtual_voicebot_backend::transport::packet [sip tcp] accepted conn_id=1 peer=192.168.10.110:48489
2025-12-21T08:28:59.319Z INFO virtual_voicebot_backend::transport::packet [sip <-] tcp conn_id=1 peer=192.168.10.110:48489 len=410
2025-12-21T08:28:59.319Z WARN virtual_voicebot_backend [main] TransactionTimeout for call_id=YOmjpkO6XrrM8tnmf41PEg..
2025-12-21T08:28:59.319Z INFO virtual_voicebot_backend [main] BYE for call_id=L1YYryKrtpk6KLm-js9aPg..
2025-12-21T08:28:59.320Z INFO virtual_voicebot_backend::sip [sip ->] 192.168.10.110:5060 -> Tcp(1) SIP/2.0 200 OK
録音も取れました。
Qiitaアドベントカレンダー2025でSIP電話を使ってずんだもんを使ったボイスボットを作りました https://t.co/QRVlUbm5n9 @YouTubeより
— 元車載ソフトエンジニアMas (@masarisu04) December 21, 2025
補足
こちらがgithubとなります。
現在developブランチで絶賛開発中です。
ローカルでしか動かせませんがもし動かしてみたいという奇特な方がいらっしゃったらREADME.mdを改修します(現在壊滅状態です。。。)
今日のまとめ(12/24の成果)
- SIP UASとして通話が成立
- RTP(PCMU/8000)を受信して録音できる
- 録音を再生できる
次(12/25)はアドベントカレンダーまとめとして、
「設計の効いた点」「一番ハマった点」「次にやること(ASR/LLM/TTSの統合)」を整理します。