はじめに
今年8月にOpenAIがRealtime APIの新機能と、gpt-realtimeという新たなモデルをリリースしました。その中で、目玉機能の一つとしてSIP経由での通話対応があります。
Realtime APIによる低遅延な音声入出力は、電話でのやりとりと相性がよいと思われます。SIP接続が可能になったことで、電話網やIP-PBXと生成AIの連携が容易になりました。
しかし、Realtime APIをSIPで接続するような事例がネット上にあまり見当たらず、自分自身も手順がわかっていなかったので、今回実際に試してみて手順をまとめました。
公式ドキュメントやネット上の記事を参考に試行錯誤で構築したため、誤った設定が含まれている可能性があります。お気づきの点があればコメントなどで教えていただけると助かります。
やりたいこと
自宅のUbuntuサーバ上にIP-PBX(Asterisk)を構築し、IP電話による内線とAIアプリを接続します。
- 電話機から 特定の内線番号(700番) に発信すると、
- Python製のAIアプリと通話できるようにする
というのがゴールです。
ローカル環境のIP-PBX(Asterisk)からOpenAIのRealtime APIに対してSIPで接続することで、WebSocketやWebRTCを経由せず、SIPだけで直接接続できるかを確認します。
流れとしては以下のイメージです。
- IP電話アプリから内線700番に発信
- Asterisk → OpenAI Realtime API エンドポイント(SIP)へ発信
-
OpenAI Realtime APIがAIアプリに webhook(
realtime.call.incoming)を送信 - AIアプリが Accept API を叩いて、AIセッションと通話を接続
環境
- 電話機: AGEphone(iOS)
- サーバ
- Ubuntu 24.04
- Asterisk 20.6
- Python(Flask)
- ngrok
- OpenAI API(Realtime API)
前提条件
- OpenAI APIを利用できるアカウントがある
- IP-PBXやAIアプリを動かせるサーバがある
- IP電話機 or IP電話アプリ(SIPクライアント)がある
- 今回は一時的な検証のため、認証などのセキュリティ機能は省略
設定作業
設定の流れ
- OpenAI API(Webhook)の設定
- AIアプリ(Webhook受信&Accept呼び出し)の設定
- IP-PBX(Asterisk)の設定
OpenAI API設定
OpenAI APIのダッシュボードからWebhookを作成します。
事前準備
- OpenAI APIを利用できるアカウントがある
- プロジェクト作成とAPIキー発行が済んでいる
このときのプロジェクトIDとAPIキーは後で使うので控えておきます。
さらに、OpenAIからWebhookを飛ばす宛先URLが必要になるため、ここでは ngrok を使って公開URLを用意します。
$ ngrok http 8001
サーバ上で上記コマンドを実行すると、以下のように公開URLが表示されるので、これもメモしておきます。
Webhook設定
-
OpenAI APIのダッシュボード画面(Settings > Project > Webhooks)でWebhookを作成します。

-
パラメータを設定します。
-
URL:先ほどの ngrok のURL(例:
https://xxxx-xx-xx-xx-8001.ngrok-free.app/openai/realtime) -
Event types:
realtime.call.incoming
作成完了時に、Signing secret が表示されるので、これも控えておきます。
-
URL:先ほどの ngrok のURL(例:
これでOpenAI API側の設定は完了です。
AIアプリの設定
サーバ上にWebhook受け口となるアプリを動作させます。
OpenAIから到達できる必要があるため、ここでは前述の ngrok を利用します。
PythonでAIアプリを動かす
公式ドキュメントを参考に、最低限応答できるシンプルなコードを作成しました(Flask使用)
import os
import requests
from flask import Flask, request, Response
from openai import OpenAI, InvalidWebhookSignatureError
app = Flask(__name__)
client = OpenAI(webhook_secret=os.environ["OPENAI_WEBHOOK_SECRET"])
OPENAI_API_KEY = os.environ["OPENAI_API_KEY"]
@app.route("/openai/realtime", methods=["POST"])
def webhook():
try:
event = client.webhooks.unwrap(request.data, request.headers)
if event.type == "realtime.call.incoming":
call_id = event.data.call_id
# 着信がきたら accept を返す
r = requests.post(
f"https://api.openai.com/v1/realtime/calls/{call_id}/accept",
headers={
"Authorization": f"Bearer {OPENAI_API_KEY}",
"Content-Type": "application/json",
},
json={
"type": "realtime",
"model": "gpt-realtime", # gpt-realtimeモデルを指定
"instructions": "あなたは電話応対のAIです。短く明瞭に日本語で話してください。",
},
timeout=3,
)
r.raise_for_status()
return Response(status=200)
except InvalidWebhookSignatureError:
return Response("Invalid signature", status=400)
except Exception as e:
print("webhook error:", e)
# Webhook側には 200 を返してリトライを防ぐ
return Response(status=200)
if __name__ == "__main__":
# 本番運用では WSGI / ASGI サーバの利用を推奨
app.run(host="0.0.0.0", port=8001)
環境変数は以下のように設定します。
-
OPENAI_API_KEY:OpenAIのAPIキー -
OPENAI_WEBHOOK_SECRET:Webhook作成時に発行された Signing secret
モデルはコード内で gpt-realtime を指定しています。
"model": "gpt-realtime",
作成したコードを起動しておきます。
先ほどの ngrok のURLにリクエストが飛んでくると、Flask 側でログが出るはずです。
$ python3 app.py
これでサーバのAIアプリ側は設定完了です。
IP-PBX(Asterisk)の設定
電話機がつながるよう内線の設定と、OpenAIに接続するための設定を行います。
設定内容
- 内線 101 / 102
- 通話確認用に2つ分の加入者を作る
- 内線 700
- 内線700にかけたらOpenAIへつなぐダイヤルプランを作成
インストール
$ sudo apt update
$ sudo apt install -y asterisk
設定
事前準備(バックアップ)
念のため設定ファイルをバックアップしておきます。
$ sudo mkdir -p "/etc/asterisk/backup_$(date +%F)"
$ sudo cp -p /etc/asterisk/*.conf "/etc/asterisk/backup_$(date +%F)/"
TLS用鍵の準備
今回は OpenAI とは SIP-TLS で接続するため、自己署名証明書(検証用途なので)を配置しておきます。
$ sudo mkdir -p /etc/asterisk/keys
$ sudo chown -R asterisk:asterisk /etc/asterisk/keys
$ sudo chmod 750 /etc/asterisk/keys
$ sudo openssl genrsa -out /etc/asterisk/keys/asterisk.key 2048
$ sudo chown asterisk:asterisk /etc/asterisk/keys/asterisk.key
$ sudo chmod 600 /etc/asterisk/keys/asterisk.key
$ sudo openssl req -new \
-key /etc/asterisk/keys/asterisk.key \
-out /etc/asterisk/keys/asterisk.csr \
-subj "/C=JP/O=example.com/CN=sip.api.openai.com"
$ sudo openssl x509 -req \
-days 365 \
-in /etc/asterisk/keys/asterisk.csr \
-signkey /etc/asterisk/keys/asterisk.key \
-out /etc/asterisk/keys/asterisk.pem
$ sudo rm /etc/asterisk/keys/asterisk.csr
$ sudo ls -l /etc/asterisk/keys
pjsip.conf
SIP 周りの設定です。ここでは PJSIP を使用します。
$ sudo vim /etc/asterisk/pjsip.conf
下記を追記(または必要に応じて調整)します。
[transport-udp]
type=transport
protocol=udp
bind=0.0.0.0
[101]
type=endpoint
context=internal
disallow=all
allow=ulaw
auth=101
aors=101
direct_media=no
[101]
type=auth
auth_type=userpass
username=101
password=<password>
[101]
type=aor
max_contacts=1
[102]
type=endpoint
context=internal
disallow=all
allow=ulaw
auth=102
aors=102
direct_media=no
[102]
type=auth
auth_type=userpass
username=102
password=<password>
[102]
type=aor
max_contacts=1
[transport-tls]
type=transport
protocol=tls
bind=0.0.0.0:0
cert_file=/etc/asterisk/keys/asterisk.pem
priv_key_file=/etc/asterisk/keys/asterisk.key
ca_list_file=/etc/ssl/certs/ca-certificates.crt
method=tlsv1_2
; お試し環境のため証明書検証しない(本番では no を推奨しません)
verify_server=no
verify_client=no
[openai]
type=aor
contact=sip:sip.api.openai.com:5061
[openai]
type=endpoint
transport=transport-tls
aors=openai
context=from-openai
disallow=all
allow=ulaw
from_domain=sip.api.openai.com
rtp_symmetric=yes
force_rport=yes
rewrite_contact=yes
direct_media=no
-
[101],[102]が内線 101 / 102 の加入者設定 -
[openai]がOpenAI(外部)のSIP接続先設定
PJSIP を利用するため、旧来の chan_sip を無効化しておきます。
$ sudo vim /etc/asterisk/modules.conf
下記を追記:
[modules]
noload = chan_sip.so
extensions.conf
ダイヤルプラン(内線番号の動作)の設定です。
$ sudo vim /etc/asterisk/extensions.conf
下記を追記します。
[internal]
exten => 101,1,Dial(PJSIP/101,30)
same => n,Hangup()
exten => 102,1,Dial(PJSIP/102,30)
same => n,Hangup()
; 700 にかけたら OpenAI (Realtime API) へ発信
exten => 700,1,Dial(PJSIP/proj_XXXXX@openai,60)
same => n,Hangup()
- 各内線番号と、それぞれの鳴動先を設定
- 内線700番をOpenAIに接続するように設定
-
proj_XXXXXの部分は、先ほどメモした OpenAI API の プロジェクトID に置き換えます
OpenAI Realtime API にSIP接続する際、Request-URI は
<project-id>@sip.api.openai.com
の形式で指定する必要があるため、このような形になっています。
Asterisk の動作確認
設定反映
サービスを再起動して設定を反映します。
$ sudo systemctl restart asterisk
Asterisk のCLIを開き、ログとSIPメッセージを表示しておきます。
$ sudo asterisk -rvvv
CLI> pjsip set logger on
内線通話テスト
内線101,102の端末を登録し、内線間で通話できるか確認します。
今回はスマホに IP電話アプリ(AGEphone)をインストールして試しました。ハードウェアIP電話機でも問題ありません。
正常に通話できない場合は、IP電話端末の設定かAsterisk側の設定に問題があります。
(自分は chan_sip を無効化し忘れてハマりました)
OpenAI Realtime API にかけてみる
ここまでの設定が問題なく動いていれば、IP電話アプリから内線700番に発信することで、サーバ上で動作中のAIアプリと通話できるようになります。
体感としては、ChatGPTの音声会話と同じくらいのレスポンスで会話できました。
実際の SIP シーケンス(抜粋)
Asterisk の CLI ログに残るSIPメッセージから、OpenAI Realtime API とSIPレベルで通信できていることが確認できます。
利用料金(参考)
gpt-realtime を利用してテストで 4 回(計 2 分程度)通話したところ、利用料は $0.11 でした。
会話時間や内容にもよりますが、gpt-5系モデルと比べるとリアルタイム音声としてはそれなりにコストがかかる印象なので、継続利用する場合はあらかじめ利用量を見積もっておいたほうがよさそうです。
gpt-realtime-mini を利用すれば、ある程度コストを抑えられそうです。
最後に
ローカル環境の IP-PBX(Asterisk) から OpenAI の Realtime API に対してSIPで接続し、電話機からAIと通話できることを確認しました。
これからやりたいこと
AI側のつくりこみ
今回は「SIP経由でつながるか」の検証が中心だったため、AIアプリ側のロジックは最小限です。
今後は Tool や MCP を利用したデータ取得・外部連携などを行うことで、具体的な業務シナリオ(予約受付、FAQ、一次窓口など)に近づけていきたいです。
セキュリティ周り
こちらも今回は検証優先であまり考慮できていません。
SIP接続後の認証、IP制限、TLSの検証有効化などを検討しないと、外部から攻撃を受けるリスクがあります。本番運用時にはこの辺りを必ず詰める必要があります。
感想
IP-PBX(Asterisk) の設定自体は、Realtime API がSIP接続に対応しているおかげで特別なことはほとんどなく、比較的簡単に接続できました。
既存のIP-PBXシステムとAIを連携させる、というユースケースが現実的になってきたと感じます。
「電話 × AI」については、これまで人が担当していた電話対応(予約受付、事務所の電話番、転送対応など)をAIに任せていくといった可能性が広がりそうです。
参考
お知らせ
こちらの記事は ctc Advent Calendar 2025 の記事です。
このあとも、ctc(中部テレコミュニケーション株式会社)のメンバーが技術にまつわる知見を投稿していきますので、ぜひご覧ください。





