この記事の最終更新日: 2026年6月1日

Webアプリに「ブラウザ通話機能」を入れたいと考えたとき、候補に上がりやすいライブラリの一つが SIP.js です。
SIP.js は、JavaScript / TypeScript で SIP 通信を扱うためのライブラリです。公式リポジトリでは、WebRTC によるリアルタイムの音声・ビデオセッション、SIP over WebSocket、インスタントメッセージ、プレゼンス、保留、転送、DTMF などを扱えるライブラリとして説明されています。(GitHub)
この記事では、SIP.js を使って SIPサーバーへ接続し、ブラウザから通話を開始するまでの基本的な流れ を初心者向けに整理します。
SIP.jsとは?
SIP.js は、ブラウザ上で SIP クライアントを実装するための JavaScript ライブラリです。
通常、電話やPBXの世界では SIP というプロトコルが使われます。一方、ブラウザで音声・映像を扱う場合は WebRTC が使われます。
SIP.js は、この2つを組み合わせて、ブラウザからSIPサーバーに接続し、音声通話やビデオ通話を実装しやすくしてくれるライブラリです。
簡単に言うと、次のような役割を持ちます。
| 役割 | 内容 |
|---|---|
| SIP通信 | SIPサーバーへの接続、REGISTER、INVITEなどを扱う |
| WebSocket通信 | ブラウザからSIPサーバーへ接続する |
| WebRTC連携 | ブラウザのマイク・スピーカーを使って音声通話する |
| 通話セッション管理 | 発信、着信、応答、終了などを扱う |
SIP.js では、通話を行うためにまず UserAgent を作成します。公式ガイドでも、通話やメッセージ送信を行うには SIP User Agent を作成する必要があると説明されています。(SIP.js)
SIP.jsで通話する全体の流れ
SIP.js でブラウザ通話を行う流れは、大きく次のようになります。
- SIPサーバーを用意する
- SIPアカウントを用意する
- SIP.jsをインストールする
- UserAgentを作成する
- SIPサーバーへWebSocket接続する
- Registererで登録する
- Inviterで通話を開始する
- 音声メディアをブラウザに接続する
最初に理解しておきたいのは、SIP.js だけでは電話システム全体は完成しないという点です。
SIP.js はあくまで ブラウザ側のSIP/WebRTCクライアント です。実際に通話するには、Asterisk、FreeSWITCH、Kamailio、OpenSIPS、商用PBX、クラウドPBXなど、SIP over WebSocket に対応したサーバー側の環境が必要になります。公式リポジトリでも、Asterisk や FreeSWITCH などの標準準拠サーバーとの互換性が説明されています。(GitHub)
事前に必要なもの
SIP.js を使う前に、最低限以下の情報が必要です。
| 項目 | 例 |
|---|---|
| SIP URI | sip:alice@example.com |
| SIPユーザー名 | alice |
| SIPパスワード | password |
| WebSocket URL | wss://sip.example.com/ws |
| 通話先SIP URI | sip:bob@example.com |
特に重要なのは WebSocket URL です。
ブラウザは通常のUDP/TCPのSIP通信を直接扱えません。そのため、SIP.jsでは SIP over WebSocket を使ってSIPサーバーと通信します。
つまり、SIPサーバー側も WebSocket 接続を受け付ける設定になっている必要があります。
SIP.jsをインストールする
npm を使う場合は、次のようにインストールします。
npm install sip.js
SIP.js は TypeScript で書かれており、公式リポジトリでも TypeScript 製のライブラリとして説明されています。(GitHub)
基本コードの全体像
まずは、SIPサーバーへ接続して通話を開始するまでの最小構成を見てみます。
import {
UserAgent,
UserAgentOptions,
Registerer,
Inviter,
SessionState,
} from "sip.js";
// 1. SIP URIを作成
const uri = UserAgent.makeURI("sip:alice@example.com");
if (!uri) {
throw new Error("SIP URIの作成に失敗しました");
}
// 2. SIPサーバーへの接続設定
const transportOptions = {
server: "wss://sip.example.com/ws",
};
// 3. UserAgentの設定
const userAgentOptions: UserAgentOptions = {
uri,
transportOptions,
authorizationUsername: "alice",
authorizationPassword: "password",
};
// 4. UserAgentを作成
const userAgent = new UserAgent(userAgentOptions);
// 5. Registererを作成
const registerer = new Registerer(userAgent);
// 6. UserAgentを開始してREGISTERする
async function connectSipServer() {
await userAgent.start();
await registerer.register();
console.log("SIPサーバーに接続・登録しました");
}
// 7. 通話を開始する
async function makeCall() {
const target = UserAgent.makeURI("sip:bob@example.com");
if (!target) {
throw new Error("通話先URIの作成に失敗しました");
}
const inviter = new Inviter(userAgent, target);
inviter.stateChange.addListener((state) => {
switch (state) {
case SessionState.Establishing:
console.log("発信中です");
break;
case SessionState.Established:
console.log("通話が開始されました");
break;
case SessionState.Terminated:
console.log("通話が終了しました");
break;
}
});
await inviter.invite();
}
公式ドキュメントでも、UserAgent を作成し、Registerer を使って登録し、Inviter で外部SIPエンドポイントへ INVITE を送信する流れが紹介されています。(GitHub)
ステップ1:UserAgentを作成する
SIP.js で最初に作るのが UserAgent です。
UserAgent は、SIPの世界における「自分自身のクライアント」を表します。
const uri = UserAgent.makeURI("sip:alice@example.com");
const userAgentOptions: UserAgentOptions = {
uri,
transportOptions: {
server: "wss://sip.example.com/ws",
},
authorizationUsername: "alice",
authorizationPassword: "password",
};
const userAgent = new UserAgent(userAgentOptions);
ここで指定している内容は、主に次の4つです。
| 設定 | 内容 |
|---|---|
uri | 自分のSIP URI |
transportOptions.server | SIPサーバーのWebSocket URL |
authorizationUsername | 認証ユーザー名 |
authorizationPassword | 認証パスワード |
UserAgent.makeURI() は、文字列から SIP.js が扱える URI オブジェクトを作成するために使います。公式ガイドでも、UserAgent.makeURI("sip:alice@example.com") のようにURIを作成する例が紹介されています。(SIP.js)
ステップ2:SIPサーバーへ接続する
UserAgentを作成しただけでは、まだSIPサーバーへ接続されていません。
接続するには、次のように start() を呼び出します。
await userAgent.start();
start() を実行すると、SIP.js は設定された WebSocket サーバーへ接続します。
この時点で行われるのは、ざっくり言うと次の処理です。
- ブラウザから
wss://...に接続する - SIP over WebSocket の通信経路を作る
- SIPメッセージを送受信できる状態にする
ここで接続に失敗する場合は、次のような原因が考えられます。
- WebSocket URLが間違っている
- SIPサーバーがWebSocketに対応していない
- TLS証明書に問題がある
- CORSやプロキシ設定に問題がある
- サーバー側でWebRTC用の設定が不足している
SIP.jsを使う場合、フロントエンド側のコードだけでなく、SIPサーバー側の WebSocket / TLS / WebRTC 設定も重要です。
ステップ3:RegistererでSIPサーバーに登録する
着信を受けたい場合は、SIPサーバーに自分の存在を登録する必要があります。
SIP.js では Registerer を使います。
const registerer = new Registerer(userAgent);
await userAgent.start();
await registerer.register();
公式ガイドでは、UserAgentを作成したあと、new Registerer(userAgent) を作成し、userAgent.start() の後に registerer.register() を呼ぶ流れが紹介されています。(SIP.js)
ここで行われるのが、SIPの REGISTER です。
REGISTERは、簡単に言うと「このSIPユーザーは今この接続先にいます」とSIPサーバーへ伝える処理です。
これにより、サーバーは着信時にブラウザクライアントへ呼び出しを転送できるようになります。
REGISTERしないと発信できないのか?
ここは少し誤解しやすいポイントです。
一般的には、ログイン処理のような感覚で REGISTER を行うことが多いです。しかし、SIPの仕組みとしては、REGISTERは主に 着信を受けるための登録 です。
発信だけであれば、サーバーや構成によっては REGISTER なしで INVITE できるケースもあります。実際にSIP.jsのGitHub Issueでも、アウトバウンドコールは登録なしで可能であるという趣旨のコメントがあります。(GitHub)
ただし、実務ではPBXやSIPサーバー側の設定で、認証済みユーザーのみ発信可能にしていることが多いです。
そのため、初心者向けには次の理解で十分です。
| 用途 | REGISTERの必要性 |
|---|---|
| 着信を受けたい | 基本的に必要 |
| 発信だけしたい | サーバー設定による |
| 一般的な内線電話アプリ | REGISTERすることが多い |
ステップ4:Inviterで通話を開始する
SIP.js で発信するには、Inviter を使います。
const target = UserAgent.makeURI("sip:bob@example.com");
if (!target) {
throw new Error("通話先URIの作成に失敗しました");
}
const inviter = new Inviter(userAgent, target);
await inviter.invite();
この invite() によって、SIPの INVITE リクエストが送信されます。
INVITEは、SIPにおける通話開始のためのリクエストです。SIP.jsの公式ガイドでも、リモートのSIPエンドポイントへ発信するには Inviter を作成し、invite() を呼び出してSIP INVITEを送信すると説明されています。(SIP.js)
イメージとしては、次のような流れです。
ブラウザ
↓ INVITE
SIPサーバー
↓
通話先ユーザー
相手が応答すると、WebRTCのメディアセッションが確立され、ブラウザ上で音声通話が始まります。
ステップ5:通話状態を監視する
通話アプリでは、現在の状態をUIに反映する必要があります。
たとえば、
- 発信中
- 呼び出し中
- 通話中
- 終了
- エラー
といった状態です。
SIP.js では、セッションの状態変化を監視できます。
inviter.stateChange.addListener((state) => {
switch (state) {
case SessionState.Establishing:
console.log("通話を確立中です");
break;
case SessionState.Established:
console.log("通話が開始されました");
break;
case SessionState.Terminated:
console.log("通話が終了しました");
break;
}
});
画面側では、この状態に応じてボタンや文言を切り替えます。
たとえば、以下のようなUI制御が考えられます。
| 状態 | UI例 |
|---|---|
| 未接続 | 「接続」ボタンを表示 |
| 登録済み | 「発信」ボタンを表示 |
| 発信中 | 「呼び出し中…」を表示 |
| 通話中 | 「通話終了」ボタンを表示 |
| 終了 | 「再発信」ボタンを表示 |
ステップ6:音声を再生できるようにする
SIP.jsで通話セッションが確立されても、ブラウザ側で音声を適切に扱わなければ、音が聞こえないことがあります。
ブラウザ通話では、主に次の2つを扱います。
| 種類 | 内容 |
|---|---|
| ローカルメディア | 自分のマイク音声 |
| リモートメディア | 相手から届く音声 |
SIP.jsのメディア処理では、ブラウザのWebRTC機能を使います。公式のAttach Mediaガイドでも、標準的なWebブラウザのWebRTC対応環境と、内蔵のSession Description Handlerを前提に説明されています。(SIP.js)
HTML側には、リモート音声用の <audio> を用意しておくのが一般的です。
<audio id="remoteAudio" autoplay></audio>
実装では、確立されたセッションからリモートのMediaStreamを取得し、audio.srcObject に設定します。
実際の書き方はSIP.jsのバージョンやSessionDescriptionHandlerの扱いによって変わるため、ここでは概念として理解しておけば十分です。
const remoteAudio = document.getElementById("remoteAudio") as HTMLAudioElement;
// 実際にはsessionDescriptionHandlerからremote streamを取得して設定する
// remoteAudio.srcObject = remoteStream;
初心者がつまずきやすいのは、SIPの接続自体は成功しているのに、音声だけ聞こえないケースです。
その場合は、SIP.jsだけでなく、WebRTC、ブラウザ権限、オーディオデバイス、ICE、NAT越えも確認する必要があります。
SIP.jsでよくあるエラー原因
SIP.jsで通話を実装するとき、よくある原因を整理します。
1. WebSocketに接続できない
WebSocket connection failed
この場合は、SIPサーバー側のWebSocket設定を確認します。
確認ポイントは以下です。
wss://のURLが正しいか- TLS証明書が有効か
- WebSocketポートが開いているか
- リバースプロキシがWebSocketを通しているか
- SIPサーバーがSIP over WebSocketに対応しているか
2. REGISTERに失敗する
REGISTERに失敗する場合は、認証情報やSIP URIの設定ミスが多いです。
確認ポイントは以下です。
authorizationUsernameが正しいかauthorizationPasswordが正しいかuriのドメインが正しいか- SIPサーバー側にユーザーが存在するか
- Realm設定が合っているか
3. 発信しても相手につながらない
発信時に INVITE を送っても相手につながらない場合があります。
確認ポイントは以下です。
- 通話先SIP URIが正しいか
- SIPサーバー側のルーティングが正しいか
- 発信権限があるか
- 内線番号の指定方法が正しいか
- PBX側のDialplanが正しいか
4. 通話はつながるが音が聞こえない
これはWebRTC系でかなり多い問題です。
確認ポイントは以下です。
- ブラウザでマイク許可が出ているか
- HTTPS環境で動かしているか
- STUN/TURNサーバーが必要な構成ではないか
- ICE candidateが正しく交換されているか
- RTPの経路がNATで遮断されていないか
<audio>要素にリモート音声を接続できているか
SIP.jsではSIPシグナリングとWebRTCメディアの両方が関係するため、「SIP接続は成功しているが音声が出ない」という状態が普通に起こります。
実務で使うときの構成例
SIP.jsを使ったブラウザ通話の構成は、たとえば次のようになります。
[ブラウザ]
React / Vue / JavaScript
SIP.js
WebRTC
|
| SIP over WebSocket
v
[SIPサーバー / PBX]
Asterisk
FreeSWITCH
Kamailio
OpenSIPS
|
| SIP / RTP
v
[通話相手]
IP電話
ソフトフォン
別ブラウザ
外線電話
Webアプリ側はSIP.jsでSIPクライアントを実装し、サーバー側ではPBXやSIPプロキシが通話制御を担当します。
業務システムに組み込む場合は、以下のような機能も必要になります。
- ログインユーザーとSIPアカウントの紐付け
- 発信先番号の管理
- 通話履歴の保存
- 録音連携
- 保留・転送
- 着信ポップアップ
- CRM連携
- 通話ステータスの管理
つまり、SIP.jsは「通話機能の部品」であり、周辺の業務ロジックは別途アプリケーション側で設計する必要があります。
SIP.jsを使うときの注意点
SIP.jsは便利ですが、単純にnpmで入れればすぐ電話アプリが完成する、というものではありません。
特に次の点には注意が必要です。
SIPサーバー側の知識が必要
SIP.jsはブラウザ側のライブラリです。
実際には、AsteriskやFreeSWITCHなどのSIPサーバー側の設定が重要になります。
特にWebRTC対応では、以下の設定が必要になることがあります。
- WebSocket
- TLS
- DTLS-SRTP
- ICE
- STUN/TURN
- Codec
- NAT設定
- Dialplan
フロントエンドだけで完結するライブラリではない点を理解しておきましょう。
HTTPS環境が必要になる
ブラウザでマイクを使う場合、基本的にはHTTPS環境が必要です。
ローカル開発では localhost で動作することがありますが、本番環境ではHTTPS化が前提になります。
音声トラブルの原因切り分けが難しい
SIP.jsを使った通話では、問題が発生したときに原因が複数に分かれます。
- SIP認証の問題
- WebSocket接続の問題
- SIPルーティングの問題
- WebRTCの問題
- NAT越えの問題
- ブラウザ権限の問題
- 音声デバイスの問題
そのため、ブラウザのコンソールログだけでなく、SIPサーバー側のログやWebRTC Internalsも確認できるようにしておくと安心です。
最小実装の流れまとめ
最後に、SIP.jsで通話開始までに必要な流れをまとめます。
1. npm install sip.js
2. UserAgentを作成する
3. WebSocket URLを設定する
4. SIP認証情報を設定する
5. userAgent.start() で接続する
6. RegistererでREGISTERする
7. Inviterで通話先にINVITEする
8. セッション状態を監視する
9. リモート音声をaudio要素に接続する
コード上の中心になるのは、以下の3つです。
| クラス | 役割 |
|---|---|
UserAgent | SIPクライアント本体 |
Registerer | SIPサーバーへの登録 |
Inviter | 発信処理 |
SIP.jsの基本は、まずこの3つを理解するところから始めるとよいです。
まとめ
SIP.jsを使うと、ブラウザ上でSIP/WebRTCを利用した音声通話機能を実装できます。
基本的な流れは、SIPアカウントを使って UserAgent を作成し、WebSocket経由でSIPサーバーへ接続し、Registerer で登録し、Inviter で通話先へ発信する、という形です。
ただし、SIP.jsはフロントエンドだけで完結するライブラリではありません。実際の通話には、SIPサーバー、WebSocket、WebRTC、STUN/TURN、NAT、音声デバイスなど、複数の要素が関係します。
そのため、最初は小さく以下の順番で確認するのがおすすめです。
- SIPサーバーへWebSocket接続できるか
- REGISTERできるか
- INVITEを送信できるか
- 相手が応答できるか
- 音声が双方向に流れるか
SIP.jsは、Webアプリに本格的な通話機能を組み込むための強力な選択肢です。まずは UserAgent、Registerer、Inviter の役割を理解し、SIPサーバー接続から通話開始までの基本フローを押さえておきましょう。

大阪のエンジニアが書いているブログ。



コメント