## 前言
由于sipjs的库实现本质还是走webtc的那套媒体协商，网络协商以及流推送的标准api，但是只提供了电话通讯的相关方法,可供定制化代码设计不够，同时也没有把webrtc常用的标准对象收集暴露出来，作者也说了要做定制得自己去收集webrtc的api去定制。

而且官方文档的描述过于简洁很多东西没有说到，还留了一些坑比如完整版usergent接入拨通电话的方法官文的例子并没有传控制音频传输的配置导致接通电话后本地声音在远端接听不到，也没有一处说到这方面的配置。

目前基于sip封了一个工具库,与框架无关

## 特性
1. 集成了封装更简洁的功能api。如注册，免打扰，开电提醒，接听，忽略，挂断
   
2. 扩展了电话通讯的相关控制功能，如控制远端流是否接收和本地流是否推送，做了通话时间记录,并做了状态追踪可以实时获取，后期还可以做通话录音相关的功能api。
   
3. 同时提供了安全销毁，由于sip通讯过程较琐碎为了避免事件绑定过多以及流的销毁问题带来内存泄露和服务器的链接注册等

4. 把常用webrtc标准对象如peerconnection,senders,recievers,mediastream,track,收集暴露出来，方便以后做功能定制化，如转接桌面音频，实时视频，发送文本文件等等

5. 后续会陆续支持电话拨打功能的集成封装

## 安装
```shell
$ yarn add @94ai/sip
```

## 使用
```js
import userAgentManager from '@94ai/sip' // 获取代理用户实例

const userAgentManager = UserAgentFactory.getUserAgentManager()
// 获取实例初始化状态
```
### 链接（由于监听需求，默认配置为 不传输本地声音到远端, 接听远端声音）
```js
userAgentManager.prepareUserAgent({ // 配置设置
  refresh(path, value) {
    userAgentStatus[path] = value // 外部想要响应状态可以实时更新外部的userAgentStatus
  }
}, { // 事件监听
  onInvite(invitation) { // 当有外呼过来
    playMedia('localAudio') // 播放模拟来电响铃
    popNotice() // 提示通知   来电了
    invitation.stateChange.addListener((state) => { // 一旦执行接听电话,注意初始化invitation不是session
      switch (state) {
        case SessionState.Initial:
          break
        case SessionState.Establishing:
          break
        case SessionState.Established: // session建立后就可拿到webrtc的各种基础api，如userAgentManager.getPeerConnection(),如userAgentManager.getSenders()等等
          const mediaElement1 = getMedia('remoteAudio') // 获取audio dom
          mediaElement1.srcObject = userAgentManager.getStream() // 获取流
          mediaElement1.play() // 播放audio
          break
        case SessionState.Terminating:
        // fall through
        case SessionState.Terminated: // 在挂断电话时候会执行
          const mediaElement2 = getMedia(id) // 获取audio dom
          mediaElement2.srcObject = null
          mediaElement2.pause() // 释放audio
          break
        default:
          throw new Error('Unknown session state.')
      }
    })
  }
})
```
### 接听
```js
const acceptInvite = () => {
  refreshShowTime() // 重新计算通话时长
  pauseMedia('localAudio') // 暂停来电铃声
  userAgentManager.acceptInvite() // 接入电话流
}
```

### 忽略
```js
const ignoreInvite = () => {
  pauseMedia('localAudio')
  userAgentManager.ignoreInvite()
}
```

### 挂断
```js
const hangUpInvite = () => {
  refreshShowTime()
  userAgentManager.hangUpInvite()
}
```

### 销毁
```js
const disconnect = () => {
  refreshShowTime()
  userAgentManager.dispose() // 一个方法安全销毁
}
```

### 传输本地声音到远端
```js
const unMuteLocalAudio = () => {
  userAgentManager.unMuteLocalAudio()
}
```
### 不传输本地声音到远端
```js
const muteLocalAudio = () => {
  userAgentManager.muteLocalAudio()
}
```
### 接听远端声音
```js
const unMuteRemoteAudio = () => {
  userAgentManager.unMuteRemoteAudio()
}
```
### 不接听远端声音
```js
const muteRemoteAudio = () => {
  userAgentManager.muteRemoteAudio()
}
```

### 获取webrpc基础api
```js
const senders = userAgentManager.getSenders()
const receivers = userAgentManager.getReceivers()
const peerConnection = userAgentManager.getPeerConnection()

```

### sip实例对象
```js
const userAgent = userAgentManager.getUserAgent()
const sessionDescriptionHandler = userAgentManager.getSessionDescriptionHandler()
const currentInvitation = userAgentManager.getCurrentInvitation()
const currentInviter = userAgentManager.getCurrentInviter()
const localMixedMediaStream = userAgentManager.getStream()
```

### 查看代理用户目前状态
```ts
interface userAgentStatus {
  connectStatus: boolean, // 是否已链接
  registerStatus: boolean, // 是否已注册
  invitatingStatus: boolean, // 是否正拨出
  incomingStatus: boolean, // 是否正来电
  answerStatus: boolean, // 是否正接听
}
const userAgentStatus: userAgentStatus = userAgentManager.getUserAgentStatue()
```

### 配置默认实例
```js
import { userAgentFactory } from '@94ai/sip'

// userAgentOptions 相关配置查看 UserAgentOptions 
userAgentFactory.getUserAgent(userAgentOptions)

// 默认配置
export const userAgentDefault = {
  authorizationPassword, // 坐席组用户密码
  authorizationUsername, // 坐席组用户名
  viaHost, // 指纹，唯一标志，用来排查线路故障
  uri: UserAgent.makeURI(sipServerHost), // sip服务地址
  logLevel: 'error', // sip日志查看等级，一般情况下生产开error,开发用debugger
  transportOptions: {
    server: webSocketServerHost // websocket协商地址
  },
}

```

That's all，如果有兴趣可以看下demo/
