1

我正在开发一个将 React.js 集成为前端框架的 Electron 应用程序,它更像是一个调用应用程序。在那个应用程序特定的用户可以有多个呼入、呼出、静音 | 取消静音,保持 | 挂断电话等。为了实现这个功能,我们有自己的 sip 服务器,为了集成该 SIP 服务器,我们在前端使用了一个名为SIP.JS的库。SIP.JS 为我们提供了几乎所有预定义的功能来拨打电话、接听电话、静音、取消静音、盲转接、出席转接等。但是在召开电话会议时,它没有相应的文档. SIP.JS 向我们说明我们可以使用FreeSWITCH以及ASTERISK为了实现功能,但根据我们的具体要求,不需要集成额外的服务器。我们还参考了电话会议的rfc 文档,但没有这样的进展。

到目前为止,我们所做的是:

  1. 注册了userAgent
  2. 集成来电代码
  3. 集成拨出电话代码
  4. 实现多个会话处理,用于多个调用
  5. 静音 | 取消静音,按住 | 取消持有。
  6. DTMF 功能
  7. 盲转,参加转
  8. 振铃所有设备

在这种电话会议的场景中,我想我们必须对传入和传出会话处理函数进行更改。

  1. 对于上下文中的注册和来电:
 const getUAConfig = async (_extension, _name) => {
    let alreadyLogin = '';
    try {
      alreadyLogin = 'yes';
      if (alreadyLogin == 'yes') {
        _displayname = _name;
        _sipUsername = _extension;
        _sipServer = 'SIP SERVER';
        _sipPassword = 'SIP PASSWORD';
        _wssServer = 'WSS SERVER;

        const uri = UserAgent.makeURI('sip:' + _sipUsername + '@' + _sipServer);
        const transportOptions = {
          wsServers: 'WSS SERVER',
          traceSip: true,
          maxReconnectionAttempts: 1,
        };

        const userAgentOptions = {
          uri: uri,
          transportOptions: transportOptions,
          userAgentString: 'App name',
          authorizationPassword: _sipPassword,
          sipExtension100rel: 'Supported',
          sipExtensionReplaces: 'Supported',
          register: true,
          contactTransport: 'wss',
          dtmfType: 'info',
          displayName: _name,
          sessionDescriptionHandlerFactoryOptions: {
            peerConnectionOptions: {
              rtcpMuxPolicy: 'negotiate',
              iceCheckingTimeout: 1000,
              iceTransportPolicy: 'all',
              iceServers: [{ urls: 'stun:stun.l.google.com:19302' }],
            },
          },
        };

        userAgent = await new UserAgent(userAgentOptions);
        const registerOptions = {
          extraContactHeaderParams: [],
        };
        registerer = await new Registerer(userAgent, registerOptions);

        registerer.stateChange.addListener((newState) => {
          
        });

        userAgent.start().then(async () => {
          console.log('Connected with WebSocket.');
          // Send REGISTER
          await registerer
            .register()
            .then((request) => {
              console.log('Successfully sent REGISTER, object is here');
              dispatch({
                type: USER_REGISTERED,
                payload: true,
              });
            })
            .catch((error) => {
              console.log('Failed to send REGISTER');
            });
        });
        return { userAgent, registerer };
      } else {
        return null;
      }
    } catch (error) {
      console.log(error.message + '');
      return null;
    }
  };
  1. 传出功能:
    const dilaerFun = (inputNumber, userAgentInfo) => {
    var session;
    var uri = UserAgent.makeURI(
      `URI which we wanna call (sip number)`
    );
    session = new Inviter(userAgentInfo, uri);
    session
      .invite()
      .then((request) => {
        console.log('Successfully sent INVITE');
        sessionInfoAdd(session);
        session.stateChange.addListener(async (state) => {
          switch (state) {
            case 'Established':
              setMissedStatus(null);
              console.log('established outgoing....');
              //outgoing call log-----
              const mediaElement = document.getElementById(
                `mediaElement${session._id}`
              );
              const remoteStream = new MediaStream();

              session.sessionDescriptionHandler.peerConnection
                .getReceivers()
                .forEach((receiver) => {
                  if (receiver.track) {
                    remoteStream.addTrack(receiver.track);
                  }
                });
              mediaElement.srcObject = remoteStream;
              mediaElement.play();
              break;
            case 'Terminated':
              console.log('terminated');
              dispatch({
                type: DEMO_STATE,
                payload: session._id,
              });
              break;
            default:
              break;
          }
        });
      })
      .catch((error) => {
        console.error(' Failed to INVITE');
        console.error(error.toString());
      });
  };

  1. 会话数组由以下人员维护:
  const sessionInfoAdd = (session) => {
    dispatch({
      type: SESSION_STORE,
      payload: session,
    });
  };
  1. 存储所有会话的变量是:
 sessionInfo:[]

注意: getUAConfig() 会在应用程序启动后立即调用。dialerFun() 当我们想拨打一个特定的号码时被调用。在 getUAConfig 和 dialerFun 中都会调用 sessionInfoAdd(),因为它们是用于呼入和呼出的代码。当 sessionInfoAdd() 被触发时,我们返回的特定会话被添加到 sessionInfo (Array) 中以维护会话。

4

1 回答 1

0

SIP.JS 只是一个库,因此您必须在 FreeSWITCH 或 Asterisk 上进行会议设置(我认为 FreeSWITCH 更好)

这样做是相当直接的,在您的应用程序级别,您需要一种在检查访问 ID 和您要添加的任何身份验证等详细信息(如 PIN 码)后将呼叫传递给该框的方法。

完成后,您可以将其转发到专门为会议设置的分机,或者通过从应用程序发送到特定网关/拨号计划来进行动态会议设置。

FreeSWITCH 软件有一个陡峭的学习曲线,但是当我做类似的事情时这对我有帮助:https ://freeswitch.org/confluence/display/FREESWITCH/mod_conference

如果你愿意,你也可以编写你自己的 conf 代码。

于 2021-10-20T07:17:04.360 回答