2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

電話機をAIにつないでみた(Asteriskとgpt-realtimeをSIP接続)

Last updated at Posted at 2025-12-15

はじめに

今年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だけで直接接続できるかを確認します。

image.png

流れとしては以下のイメージです。

  1. IP電話アプリから内線700番に発信
  2. AsteriskOpenAI Realtime API エンドポイント(SIP)へ発信
  3. OpenAI Realtime APIAIアプリに webhook(realtime.call.incoming)を送信
  4. 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クライアント)がある
  • 今回は一時的な検証のため、認証などのセキュリティ機能は省略

設定作業

設定の流れ

  1. OpenAI API(Webhook)の設定
  2. AIアプリ(Webhook受信&Accept呼び出し)の設定
  3. IP-PBX(Asterisk)の設定

OpenAI API設定

OpenAI APIのダッシュボードからWebhookを作成します。

事前準備

  • OpenAI APIを利用できるアカウントがある
  • プロジェクト作成とAPIキー発行が済んでいる

このときのプロジェクトIDAPIキーは後で使うので控えておきます。

さらに、OpenAIからWebhookを飛ばす宛先URLが必要になるため、ここでは ngrok を使って公開URLを用意します。

$ ngrok http 8001

サーバ上で上記コマンドを実行すると、以下のように公開URLが表示されるので、これもメモしておきます。

image.png

Webhook設定

  1. OpenAI APIのダッシュボード画面(Settings > Project > Webhooks)でWebhookを作成します。
    image.png

  2. Createボタンから新規Webhookを作成します。
    image.png

  3. パラメータを設定します。

    • URL:先ほどの ngrok のURL(例:https://xxxx-xx-xx-xx-8001.ngrok-free.app/openai/realtime
    • Event typesrealtime.call.incoming

    image.png

    作成完了時に、Signing secret が表示されるので、これも控えておきます。

作成後、下記のように一覧に表示されます。
image.png

これで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 を利用すれば、ある程度コストを抑えられそうです。

image.png


最後に

ローカル環境の 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(中部テレコミュニケーション株式会社)のメンバーが技術にまつわる知見を投稿していきますので、ぜひご覧ください。

2
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?