YeIM-CallKit
是基于LiveKit WebRTC SDK
的实时音视频聊天 uni-app
原生插件,支持 Android 和 iOS,无需第三方服务支持,本地架设流媒体服务端,适合内网、公网、私有化、私密化部署。
流媒体后端服务使用开源 SFU 架构的LiveKit-Server
媒体服务器,内置 TURN 中继服务,无需第三方支持即可实现公网转发。
目前该原生插件暂时仅支持一对一视频聊天、一对一语音聊天,未来会不断支持多对多、屏幕分享等多样化功能(注:不支持 x86 架构,无法使用模拟器运行通话)。
该原生插件不包含 IM 相关服务,信令等呼叫操作请自行使用其他方式进行,例如 WebSocket、HTTP。
YeIM-CallKit
是音视频聊天客户端插件,LiveKit-Server
是支撑音视频聊天的媒体后端服务。
使用YeIM-CallKit
必须先运行LiveKit-Server
,下面将告诉你怎么运行它。
curl -sSL https://raw.githubusercontent.com/wzJun1/YeIM-CallKit/main/install.sh | bash
或者使用国内镜像
curl -sSL https://raw.nuaa.cf/wzJun1/YeIM-CallKit/main/install.sh | bash
brew install livekit
64 位 Windows10 以上操作系统下载:https://github.com/wzJun1/YeIM-CallKit/raw/main/x64-server.exe
# --dev 以开发模式启动# 内网环境下推荐以开发模式启动做测试# 公网请勿以开发模式启动,因为没有启动TURN中继服务,而一般情况无法正常打洞,也就无法正常通话livekit-server --dev
# --config 以配置文件启动livekit-server --config config.yaml
# --dev 以开发模式启动# 内网环境下推荐以开发模式启动做测试# 公网请勿以开发模式启动,因为没有启动TURN中继服务,而一般情况无法正常打洞,也就无法正常通话x64-server.exe --dev
# --config 以配置文件启动x64-server.exe --config config.yaml
https://raw.githubusercontent.com/wzJun1/YeIM-CallKit/main/config-内网用.yaml
https://raw.githubusercontent.com/wzJun1/YeIM-CallKit/main/config-外网用.yaml
如果是在内网环境下使用,那么无论使用--dev
或者--config
启动都是可以的。启动完成后仅需将本地 7880 端口套一层 SSL 即可正常使用YeIM-CallKit
,套 SSL 方法下面会说。
如果是在公网环境下使用,请使用--config
配合配置文件启动
1.准备一个域名,例如
livekit-server.xxxxxx.com
,将域名解析到内网 IP
2.准备这个域名的 SSL/TLS 证书,即便使用免费证书Let's Encrypt
亦可,证书可到 https://freessl.cn/ 进行免费申请,如果内网服务器使用了宝塔面板,也可直接申请免费证书
3.按照上述方法启动livekit-server
或者以配置文件启动均可(以配置文件启动请自行修改 api-key 和 api-secret),服务默认端口为 7880
4.使用Nginx
反代这个本地服务,并开启 SSL,这里附一份Nginx 配置文件案例,仅供参考
1.确保公网服务器环境纯净,因 TURN 服务需占用 443 端口,所以请保证其他程序未占用 443,包括 Nginx。
2.防火墙规则开启端口:80,443,3478,4431,7880,7881,30000 到 60000 端口,请一定确认以上端口 TCP/UDP 防火墙均为允许通过,否则将无法正常使用
3.准备两个域名,例如livekit-server.xxxxxx.com
livekit-turn.xxxxxx.com
,将域名解析到公网 IP
4.准备这两个域名的 SSL/TLS 证书,即便使用免费证书Let's Encrypt
亦可,证书可到 https://freessl.cn/ 进行免费申请,如果内网服务器使用了宝塔面板,也可直接申请免费证书
5.以配置文件启动livekit-server
,服务默认端口为 7880,TURN 端口为 443。配置文件演示如下:
config.yaml
port: 7880log_level: infortc:tcp_port: 7881port_range_start: 50000port_range_end: 60000use_external_ip: truekeys:这里填自定义的api-key: 这里填自定义的api-secert,32位turn:enabled: truedomain: livekit-turn.xxxxxx.com(这里替换成你自己的域名)tls_port: 443cert_file: 这里填livekit-turn.xxxxxx.com的TLS证书地址key_file: 这里填livekit-turn.xxxxxx.com的TLS证书密钥地址
6.使用
Nginx
反代这个本地服务,并开启 SSL,这里附一份Nginx 配置文件案例,仅供参考
server{listen 80;#如果作为单机实例的情况:内网环境使用音视频通话不需要TURN,可直接使用443端口。这里使用了4431是因为需要在单机公网环境下使用TURN,非负载架构TURN必须使用443端口,开发者可根据实际情况修改。#一般情况如果是公网部署,就按此配置即可listen 4431 ssl http2;server_name 你的域名;index index.php index.html index.htm default.php default.htm default.html;root /www/wwwroot/home;#SSL-START SSL相关配置,请勿删除或修改下一行带注释的404规则#error_page 404/404.html;ssl_certificate /www/server/panel/vhost/cert/fullchain.pem;ssl_certificate_key /www/server/panel/vhost/cert/privkey.pem;ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;ssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;ssl_prefer_server_ciphers on;ssl_session_cache shared:SSL:10m;ssl_session_timeout 10m;add_header Strict-Transport-Security "max-age=31536000";error_page 497 https://$host$request_uri;#SSL-END#反向代理规则location /{proxy_pass http://127.0.0.1:7880;proxy_set_header Host $host;proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header REMOTE-HOST $remote_addr;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection $connection_upgrade;proxy_http_version 1.1;}}
https://livekit-server.xxxxxx.com:4431
,正常情况显示OK
字样。LiveKit-Backend
是操控LiveKit-Server
的集成 SDK,可以对通话房间Room
使用 API 进行一系列控制,也可以用于生成 Token。
LiveKit-Backend
拥有多种语言的实现,包括 JavaScript、GO、Python、Java、PHP,这里可以查看相关 SDK 源码:https://docs.livekit.io/references/client-sdks/
LiveKit-Server
为通话者创建的房间,用户需要在房间内通过推送视频流和音频流进行交互。
用户进入房间的凭证。
你可以在你自己的项目中安装LiveKit-Backend
依赖,从而实现对通话房间Room
使用 API 进行一系列控制,也可以用于生成 Token。
npm install livekit-server-sdk --save
import express from 'express';import { AccessToken } from 'livekit-server-sdk';const createToken = () => {const room = '房间号';const identity = '用户ID标识';const at = new AccessToken('api-key', 'secret-key', {identity: participantName,});at.addGrant({ roomJoin: true, room: room });return at.toJwt();};const app = express();const port = 3000;app.get('/getToken', (req, res) => {res.send(createToken());});app.listen(port, () => {console.log(`Server listening on port ${port}`);});
<dependencies><dependency><groupId>io.livekit</groupId><artifactId>livekit-server</artifactId><version>0.5.3</version></dependency></dependencies>
AccessToken token = new AccessToken("apiKey", "secret");token.setIdentity("用户ID标识");token.addGrants(new RoomJoin(true), new RoomName("房间号"));System.out.println("New access token: " + token.toJwt())
composer require agence104/livekit-server-sdk
$room = '房间号';$identity = '用户ID标识';$tokenOptions = (new AccessTokenOptions())->setIdentity($identity);$videoGrant = (new VideoGrant())->setRoomJoin();->setRoomName($room);$token = (new AccessToken('api-key', 'secret-key'))->init($tokenOptions)->setGrant($videoGrant)->toJwt();
go get github.com/livekit/server-sdk-go
import ("http""log""time"lksdk "github.com/livekit/server-sdk-go""github.com/livekit/protocol/auth")func getJoinToken(apiKey, apiSecret, room, identity string) string {config = readFile(config)at := auth.NewAccessToken(os.GetEnv("api-key"), os.GetEnv("secret"))grant := &auth.VideoGrant{RoomJoin: true,Room: room,}at.AddGrant(grant).SetIdentity(identity).SetValidFor(time.Hour)return at.ToJWT()}func main() {http.HandleFunc("/getToken", func(w http.ResponseWriter, r *http.Request) {w.write(getJoinToken())})log.Fatal(http.ListenAndServe(":8080", nil))}
pip install livekit-server-sdk-python
import livekitgrant = livekit.VideoGrant(room_join=True, room="房间号")access_token = livekit.AccessToken(os.environ("api-key"), os.environ("secret"), grant=grant, identity="用户ID标志", name="Bob")token = access_token.to_jwt()
插件不包含 IM 相关服务,信令等呼叫操作请自行使用其他方式进行,例如 WebSocket、HTTP
以下演示通话流程:
呼叫方
用户通过点击事件或者其他事件调用startC2CVideoCall
方法进入呼叫页面,此时项目开发者应通过 WebSocket 或者 HTTP 通知接听方
调用answerC2CVideoCall
进入接听页面,接听方
在接听页面点击接听按钮,双方开始进入通话。
startC2CVideoCall(options, callback) -> Void
字段 | 类型 | 必填 | 默认 | 说明 |
---|---|---|---|---|
wsURL | String | 是 | 空 | 媒体服务器域名,必须使用 wss 协议 |
token | String | 是 | 空 | 用户凭证 |
userInfo | Object | 是 | 空 | 本人用户信息 |
callerUserInfo | Object | 是 | 空 | 对方用户信息 |
videoOptions | Object | 否 | 空 | 可选视频参数 |
audioOptions | Object | 否 | 空 | 可选音频参数 |
callRing | String | 否 | 空 | 呼叫铃声,支持本地和网络 URL,为空则不播放 |
answerRing | String | 否 | 空 | 接听铃声 |
hungupRing | String | 否 | 空 | 挂断铃声 |
字段 | 类型 | 必填 | 默认 | 说明 |
---|---|---|---|---|
nickname | String | 是 | 空 | 用户昵称 |
avatar | String | 是 | 空 | 头像 URL |
identity | String | 否 | 空 | 用户 ID 标志 |
字段 | 类型 | 必填 | 默认 | 说明 |
---|---|---|---|---|
position | String | 否 | front | 初始摄像头,可选值 |
encoding | String | 否 | QHD | 视频清晰度,可选值 |
字段 | 类型 | 必填 | 默认 | 说明 |
---|---|---|---|---|
bitrate | Number | 否 | 20000 | 音频码率 |
dtx | Boolean | 否 | true | 开启后将再静弱音场景下降低传输速率,减少带宽占用,适合语音聊天,不建议音乐相关对音频质量要求高的场景开启。 |
noiseSuppression | Boolean | 否 | true | 噪声抑制 |
echoCancellation | Boolean | 否 | true | 回声消除 |
autoGainControl | Boolean | 否 | true | 自动增益 |
highPassFilter | Boolean | 否 | true | 高音过滤 |
typingNoiseDetection | Boolean | 否 | true | 打字噪音检测 |
视频清晰度 | 分辨率 | FPS | 码率 |
---|---|---|---|
QVGA | 320x180 | 15 | 125kbps |
VGA | 640x360 | 30 | 400kbps |
QHD | 960x540 | 30 | 800kbps |
HD | 1280x720 | 30 | 2500kbps |
FHD | 1920x1080 | 30 | 4000kbps |
const YeIMCallKit = uni.requireNativePlugin('wz-YeIMCallKit');YeIMCallKit.startC2CVideoCall({wsURL: 'wss://媒体服务器反代你的域名,如以上案例中的wss://livekit-server.xxxxxx.com:4431',token: '通过后端服务生成的Token。通话双方生成Token传入的用户ID不能一样,传入的房间号必须一样',userInfo: {nickname: '对方用户昵称',avatar: '对方头像URL',},},(e) => {console.log(e);},);
answerC2CVideoCall(options, callback) -> Void
参数同 startC2CVideoCall 接口
const YeIMCallKit = uni.requireNativePlugin('wz-YeIMCallKit');YeIMCallKit.answerC2CVideoCall({wsURL: 'wss://媒体服务器反代你的域名,如以上案例中的wss://livekit-server.xxxxxx.com:4431',token: '通过后端服务生成的Token,通话双方生成Token传入的用户ID不能一样,传入的房间号必须一样',userInfo: {nickname: '对方用户昵称',avatar: '对方头像URL',},},(e) => {console.log(e);},);
startC2CVoiceCall(options, callback) -> Void
字段 | 类型 | 必填 | 默认 | 说明 |
---|---|---|---|---|
wsURL | String | 是 | 空 | 媒体服务器域名,必须使用 wss 协议 |
token | String | 是 | 空 | 用户凭证 |
userInfo | Object | 是 | 空 | 本人用户信息 |
callerUserInfo | Object | 是 | 空 | 对方用户信息 |
audioOptions | Object | 否 | 空 | 可选音频参数 |
callRing | String | 否 | 空 | 呼叫铃声,支持本地和网络 URL,为空则不播放 |
answerRing | String | 否 | 空 | 接听铃声 |
hungupRing | String | 否 | 空 | 挂断铃声 |
字段 | 类型 | 必填 | 默认 | 说明 |
---|---|---|---|---|
nickname | String | 是 | 空 | 用户昵称 |
avatar | String | 是 | 空 | 头像 URL |
identity | String | 否 | 空 | 用户 ID 标志 |
字段 | 类型 | 必填 | 默认 | 说明 |
---|---|---|---|---|
bitrate | Number | 否 | 20000 | 音频码率 |
dtx | Boolean | 否 | true | 开启后将再静弱音场景下降低传输速率,减少带宽占用,适合语音聊天,不建议音乐相关对音频质量要求高的场景开启。 |
noiseSuppression | Boolean | 否 | true | 噪声抑制 |
echoCancellation | Boolean | 否 | true | 回声消除 |
autoGainControl | Boolean | 否 | true | 自动增益 |
highPassFilter | Boolean | 否 | true | 高音过滤 |
typingNoiseDetection | Boolean | 否 | true | 打字噪音检测 |
const YeIMCallKit = uni.requireNativePlugin('wz-YeIMCallKit');YeIMCallKit.startC2CVoiceCall({wsURL: 'wss://媒体服务器反代你的域名,如以上案例中的wss://livekit-server.xxxxxx.com:4431',token:'通过LiveKit-Backend生成的Token,通话双方生成Token传入的用户ID不能一样,传入的房间号必须一样',userInfo: {nickname: '对方用户昵称',avatar: '对方头像URL',},},(e) => {console.log(e);},);
answerC2CVoiceCall(options, callback) -> Void
参数同 answerC2CVoiceCall 接口
const YeIMCallKit = uni.requireNativePlugin('wz-YeIMCallKit');YeIMCallKit.answerC2CVoiceCall({wsURL: 'wss://媒体服务器反代你的域名,如以上案例中的wss://livekit-server.xxxxxx.com:4431',token:'通过LiveKit-Backend生成的Token,通话双方生成Token传入的用户ID不能一样,传入的房间号必须一样',userInfo: {nickname: '对方用户昵称',avatar: '对方头像URL',},},(e) => {console.log(e);},);
状态码:Code | 描述 |
---|---|
10001 | 服务端 URl 错误 |
10002 | Token 错误 |
10003 | 连接错误,通用 |
10004 | 方法参数错误 |
10005 | 呼叫拒绝 |
10006 | 通话挂断,异常挂断。一般本地的网络连接异常断开,没网或者 1 分钟内多次重连无效会导致此情况,对方网络断开或者异常也会导致此情况 |
10007 | 无摄像头和麦克风权限 |
20001 | 双方对接完毕,开始通话 |
20002 | 通话挂断,手动挂断 |
V1 版本包含 1v1 语音、视频通话。(插件市场 249 元版本:查看,直接购买即可,如果需要离线打包,需要单独再付 3000 元离线包费用,具体请联系开发者)
V2.0 版本包括 1v1 语音、视频通话,多人语音视频通话,会议室。(价格 15000 元) V2.1 版本包括 1v1 语音、视频通话,多人语音视频通话,会议室,视频人像背景虚化+背景切换。(价格 23000 元)
具体功能见下
V2 版本新增了多人语音视频通话、会议室功能,需单独付费。
V2 版本具体功能新增如下:
请联系作者索取演示 App,因通话和会议室的开放性和部分政策原因,所以不提供公开演示 App.
如需购买 V2 版本,请确认您的业务是完全正规合法
的,否则不予提供任何服务.
QQ 号:2654166809
微信号:Sentinel-110
微信二维码:
作者只有这两个联系方式,其他联系方式均为诈骗,请勿采信
项目禁止用于任何违法犯罪途径,一旦发现截图直接举报【公安部网络违法犯罪举报网站(http://cyberpolice.mps.gov.cn/wfjb/)】
1.0.9 - 2024-01-29
Android
通话时间超过 2 小时网络异常断开的问题1.0.8 - 2023-12-29
Android
打开悬浮窗后进入其他 App 导致的通话中断iOS
因网络异常或房间错误导致的无法退出通话1.0.7 - 2023-09-20
Android
语音通话啸叫1.0.6 - 2023-09-13
Android
修复因 1.0.5 版本引出的视频通话异常1.0.5 - 2023-09-03
Android
通话 SDK 版本升级至1.2.2
Android
修复网络状态异常下本地视频显示问题Android
iOS
语音通话扬声器设置默认开启Android
iOS
移除因对方网络状态异常导致的呼叫方挂断iOS
修复悬浮窗异常1.0.4 - 2023-08-28
1.0.3 - 2023-07-08
1.0.2 - 2023-06-06