You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用sip.js库连接Linphone SIP服务器失败,求解决方案

问题

使用onsip.com的sip.js作为Web SIP客户端,尝试连接Linphone SIP服务,运行代码后出现WebSocket连接失败错误。

相关代码

/* eslint-disable @typescript-eslint/no-explicit-any */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { UserAgentOptions, Web } from "sip.js";
import { SimpleUserDelegate } from "sip.js/lib/platform/web/simple-user/simple-user-delegate";
import { getButton, getE, getVideo } from "./scripts/demo-utils";

const domainOnSip = "sipjs.onsip.com";
export let webSocketServer="wss://edge.sip.onsip.com";

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const domainLinphone = 'sip.linphone.org';
const webSocketServerLinphone="wss://sip.linphone.org";

const iamUser = "nidza";
webSocketServer = webSocketServerLinphone;

console.info('Hackey running...', Web);

const delegate: SimpleUserDelegate={
  onCallReceived: async () => {
    console.log('Incoming Call!');
    await simpleUser2.answer();
  }
};

const userAgentOptions = {
  sessionDescriptionHandlerFactoryOptions: {
    peerConnectionConfiguration: {
      iceServers: [{
        urls: "stun:stun.l.google.com:19302"
      }, {
        username: "nidza",
        credential: "***********"
      }]
    },
  }
};

// Options for SimpleUser
const options: Web.SimpleUserOptions={
  userAgentOptions: userAgentOptions,
  aor: `sip:${iamUser}@${domainLinphone}`,
  media: {
    constraints: { audio: false, video: true },
    local: {
      video: getVideo("videoLocalAlice")
    },
    remote: {
      video: getVideo("videoRemoteAlice")
    }
  }
};

const options2: Web.SimpleUserOptions={
  aor: `sip:zlatnaspirala@${domainLinphone}`,
  media: {
    constraints: { audio: false, video: true },
    local: {
      video: getVideo("videoLocalBob")
    },
    remote: {
      video: getVideo("videoRemoteBob")
    }
  },
  delegate: delegate
};


// Construct a SimpleUser instance
const simpleUser=new Web.SimpleUser(webSocketServer, options);
const simpleUser2=new Web.SimpleUser(webSocketServer, options2);

simpleUser.connect()
  .then(() => {

    console.info("status: sip server connected.");
    (getE('callIdList') as HTMLInputElement).disabled=false;
    (getButton('connectUser')).disabled=true;
    (getButton('registerUser')).disabled=false;

    simpleUser.register().then(() => {

      console.info("status: registered.");
      getButton('registerUser').disabled=true;
      getButton('callBtn').disabled=false;
      getButton('callBtn').classList.add('cooliano');
      getButton('callBtn').addEventListener('click', (e) => {

        console.log(">>>"+(getE('callIdList') as HTMLSelectElement).selectedOptions[0].innerText)
        console.log(">>>"+(getE('callIdList') as HTMLSelectElement).selectedIndex)
        const emailLocal=(getE('callIdList') as HTMLSelectElement).selectedOptions[0].innerText;

        const curAddress=`sip:${emailLocal}`;
        // const curAddress = `sip:bob@${domain}`;
        simpleUser.call(curAddress, undefined, {
          requestDelegate: {
            onAccept: (e) => {
              console.info(`status: ${(e as any).message.from.uri.normal.user} INVITE accepted from ${(e as any).message.to.uri.normal.user}`);
              getButton('hangupBtn').disabled=false;
              (getButton('hangupBtn')).addEventListener('click', () => {
                //

                simpleUser.hangup().then(() => {
                  console.log("just test hangup")
                })
              })
            },
            onReject: (response) => {
              console.info(`status: INVITE rejected`);
              let message=`Session invitation to  rejected.\n`;
              message+=`Reason: ${response.message.reasonPhrase}\n`;
              alert(message);
            }
          },
          withoutSdp: false
        })
          .catch((error: Error) => {
            console.error(`error: failed to begin session`, error);
            alert(` Failed to begin session.\n`+error);
          });
      })

    }).catch((error: Error) => {
      console.error("error in registration:", error);
    });

  }).catch((error: Error) => {
    console.error("error in connection:", error);
  });

simpleUser2.connect()
  .then(() => {
    simpleUser2.register().then(() => {
      console.log("Nice reg bob");
    }).catch((error: Error) => {
      console.log("Error in registration:", error);
    });
  }).catch((error: Error) => {
    console.log("Error:", error);
  });

运行错误

transport.js:197 WebSocket connection to 'wss://sip.linphone.org/' failed: 
_connect @ transport.js:197
logger-factory.js:85 Sat Jan 07 2023 21:23:45 GMT+0100 (Central European Standard Time) | sip.Transport | WebSocket error occurred.
print @ logger-factory.js:85
hackeyWeb.ts:108 error in connection: Error: WebSocket closed wss://sip.linphone.org (code: 1006)
    at Transport.onWebSocketClose (transport.js:337:1)
    at WebSocket.<anonymous> (transport.js:199:1)

解决建议

  • 确认Linphone的WebSocket服务端点:Linphone的WebSocket服务可能不是直接使用wss://sip.linphone.org,建议尝试带端口或路径的常见配置,比如wss://sip.linphone.org:443/ws或wss://sip.linphone.org:8089。
  • 修复ICE服务器配置:当前ICE服务器配置中第二个条目缺少urls字段,这会导致配置无效。如果使用TURN服务器,补充urls字段;如果不需要TURN,暂时移除第二个条目,仅保留STUN服务器测试。
  • 检查跨域限制:若网页在本地或其他域名下运行,Linphone服务器可能未配置CORS允许你的域名访问。通过浏览器开发者工具Network面板查看请求的CORS响应头,确认是否存在访问限制。
  • 验证TLS证书:浏览器会校验WebSocket服务器的TLS证书,直接在浏览器访问https://sip.linphone.org,查看证书是否有效、是否被信任。
  • 简化连接逻辑:暂时移除simpleUser2的连接代码,先测试单个用户连接成功后,再添加第二个用户的逻辑,避免资源冲突或服务器限制。

内容的提问来源于stack exchange,提问作者Nikola Lukic

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 04:50:23