uni-app技術分享|開源demo視頻呼叫arcall uni-app端技術實現


uniapp_arcall

介紹

基本

uniapp_arcall 是通過 uniapp 實現的語音通話、視頻通話以及相關配套的呼叫邀請。
解決向指定用戶發起呼叫通知,對方接受后進行通話的場景需求。

呼叫邀請基本流程

graph TD A[主叫] -->|發起呼叫|B{被叫收到呼叫} A -->|收到被叫接聽|C[主叫執行 RTC] A -->|收到被叫拒絕|G[相關邏輯] B -->D[被叫接聽] B -->E[被叫拒絕] D -->|通知主叫接聽|A D -->F[被叫執行 RTC] E -->|通知主叫拒絕|A B -->H[60s 無操作邀請自動失敗]

通話基本流程

graph LR A[初始化 RTC 實例] -->|采集音視頻|B[加入房間] B -->|本地采集音視頻| C[發布並渲染音視頻] B -->|通過回調獲取遠端音視頻| D[渲染遠端音視頻]

arcall 具體實現

demo 源碼 地址

呼叫邀請相關邏輯

引入呼叫邀請所需插件

// rtm 實時消息引入
const rtmModule = uni.requireNativePlugin('AR-RtmModule');

呼叫邀請初始化

uniapp_arcall的是項目啟動就登陸 RTM,因此寫在 onLaunch中,調試時會發生以下錯誤

Error: [JS Framework] Failed to receiveTasks, instance (1) is not available.

原因是多次將 RTM 實例初始化,會影響到 RTM 相關的使用請將程序殺死后在進行調試

// 初始化回調
await rtmModule.setCallBack(res => {
			switch (res.rtmEvent) {
			// SDK 與 RTM 系統的連接狀態發生改變回調。
			case 'onConnectionStateChanged':
				break;
				// 收到點對點消息回調
			case 'onPeerMessageReceived':
			
				break;
				// 被訂閱用戶在線狀態改變
			case 'onPeersOnlineStatusChanged':
				
				break;
				// 返回給主叫:被叫已接受呼叫邀請
			case 'onLocalInvitationAccepted':
				
				break;
				// 返回給主叫:呼叫邀請已被取消
			case 'onLocalInvitationCanceled':
				
				break;
				// 返回給主叫:呼叫邀請進程失敗
			case 'onLocalInvitationFailure':
				
				break;
				// 返回給主叫:被叫已收到呼叫邀請
			case 'onLocalInvitationReceivedByPeer':
				
				break;
				// 返回給主叫:被叫已拒絕呼叫邀請
			case 'onLocalInvitationRefused':
			
				break;
				// 返回給被叫:接受呼叫邀請成功
			case 'onRemoteInvitationAccepted':
			
				break;
				// 返回給被叫:主叫已取消呼叫邀請
			case 'onRemoteInvitationCanceled':
				
				break;
				// 返回給被叫:來自主叫的呼叫邀請進程失敗
			case 'onRemoteInvitationFailure':
				
				break;
				// 返回給被叫:收到一個呼叫邀請
			case 'onRemoteInvitationReceived':
			
				break;
				// 返回給被叫:拒絕呼叫邀請成功
			case 'onRemoteInvitationRefused':
				
				break;
			default:
				break;
		}
	})
// 初始化實例
await rtmModule.createInstance({
		"appId": "你的 appid"
	}, res => {
		console.log(res);
	})
// 登錄 RTM 系統
await rtmModule.login({
	"token": "",
	"userId": "本地用戶標識"
}, (res) => {
	console.log("登錄 RTM 系統", res);
})
// // 使用 RTM 呼叫邀請(設置邀請呼叫實例的監聽器)
await rtmModule.setCallEventListener();

主叫

  • 查詢呼叫用戶是否在線

    rtmModule.queryPeersOnlineStatus({
    			"peerIds": ["呼叫用戶"]
    		}, (res) => {
    			console.log(res);
    		})
    
  • 呼叫用戶在線時發起呼叫並訂閱

    • 發起呼叫
      把本地創建的頻道房間發送過去
    rtmModule.sendLocalInvitation({
    			"calleeId": calleeId, // 被呼叫者的 user ID
    			"content": JSON.stringify(info) // 邀請內容
    		}, (res) => {
    			resolve(res.code);
    		})
    
    • 訂閱(獲取對方在線狀態)
      當結束通話或結束邀請時記得取消訂閱
    rtmModule.subscribePeersOnlineStatus({
    		"peerIds": ["對方 uid"]
    	}, (res) => {
    		//smething
    		console.log("訂閱指定單個或多個用戶的在線狀態", res);
    	})
    
  • 主叫取消呼叫

rtmModule.cancelLocalInvitation({
  		"calleeId": calleeId, // 被呼叫者的 user ID
  		"content": JSON.stringify(info) // 邀請內容
  	}, (res) => {
  		console.log("取消給對方的呼叫邀請", res);
  	});

被叫

通過回調 onRemoteInvitationReceived 收到主叫

  • 拒絕呼叫
rtmModule.refuseRemoteInvitation({
			"calleeId": userId,
			"response": JSON.stringify(info) /邀請內容
		}, (res) => {
		});
  • 接受呼叫
rtmModule.acceptRemoteInvitation({
			"calleeId": calleeId, // 供被叫獲取主叫的用戶 ID
			"response": info ? JSON.stringify(info) : "" // 邀請響應
		}, (res) => {
		});
// 訂閱對方在線狀態
...

相關提示

相關的提示、邏輯都可通過回調來進行操作

通話相關邏輯

視頻組件必須實在 nvue 頁面

<AR-CanvasView ref="location" style="flex: 1;" />

不管是主叫還是被叫,收到接聽的回調后就可以進入 RTC 的相關邏輯

  • 引入插件
const rtcModule = uni.requireNativePlugin('AR-RtcModule');
  • 初始化
// 初始化回調 
await rtcModule.setCallBack(res => {
		switch (res.engineEvent) {
			case "onConnectionLost":
				console.log("onConnectionLost", res);
				break;
				// 網絡連接狀態已改變回調
			case "onConnectionStateChanged":
				console.log("網絡連接狀態已改變回調", res);
				break;
				// 發生警告回調
			case "onWarning":
				
				break;
				// 發生錯誤回調
			case "onError":
				
				break;
				// 加入頻道成功回調
			case "onJoinChannelSuccess":
				// 本地渲染
			
				break;
				// 遠端用戶加入當前頻道回調
			case "onUserJoined":
			
				break;
				// 遠端用戶離開當前頻道回調
			case "onUserOffline":
				console.log("遠端用戶離開當前頻道回調", res);
			
				break;
				// 網絡連接狀態已改變回調
			case "onConnectionStateChanged":
			
				break;
				// 已顯示遠端視頻首幀回調
			case "onFirstRemoteVideoFrame":
				break;
			case "onFirstRemoteVideoDecoded":
			
				break;
				// 遠端用戶視頻狀態發生已變化回調(當頻道內的用戶超過 17 時,該回調可能不准確)
			case "onRemoteVideoStateChanged":
			
				break;
				// 	// 本地網絡類型發生改變回調
				// case "onNetworkTypeChanged":
				// 	break;
				// 	// 網絡連接中斷
				// case "onConnectionLost":
				// 	break;

				// 	// 遠端音頻狀態發生改變回調
				// case "onRemoteAudioStateChanged":
				// 	break;
				// 	// 本地音頻狀態發生改變回調
				// case "onLocalAudioStateChanged":
				// 	break;
				// 	// 本地視頻狀態發生改變回調
				// case "onLocalVideoStateChanged":
				// 	break;
				// 	// 重新加入頻道回調
				// case "onRejoinChannelSuccess":
				// 	break;
				// 	// 離開頻道回調
				// case "onLeaveChannel":
				// 	break;
				// 已發送本地音頻首幀回調
				// case "onFirstLocalAudioFrame":
				// 	break;
				// 	// 已顯示本地視頻首幀回調
				// case "onFirstLocalVideoFrame":
				// 	break;
				// 	// Token 服務即將過期回調
				// case "onTokenPrivilegeWillExpire":
				// 	break;
				// 	// Token 過期回調
				// case "onRequestToken":
				// 	break;
				// 	// 用戶角色已切換回調(直播場景下)
				// case "onClientRoleChanged":
				// 	break;
				// 	// 本地或遠端視頻大小或旋轉信息發生改變回調
				// case "onVideoSizeChanged":
				// 	break;
				// 	// 通話中遠端音頻流的統計信息回調
				// case "onRemoteAudioStats":
				// 	break;
				// 	// 當前通話統計回調。 該回調在通話中每兩秒觸發一次
				// case "onRtcStats":
				// 	break;
				// 	// 通話中每個用戶的網絡上下行 last mile 質量報告回調
				// case "onNetworkQuality":
				// 	break;
				// 	// 通話中本地視頻流的統計信息回調
				// case "onLocalVideoStats":
				// 	break;
				// 	// 通話中本地音頻流的統計信息回調
				// case "onLocalAudioStats":
				// 	break;
				// 	// 通話中遠端視頻流的統計信息回調
				// case "onRemoteVideoStats":
				// 	break;
		}
		
});
// 初始化實例
await rtcModule.create({
	"appId": '你的 appid'
}, res => {
	console.log('初始化實例 rtc', res);
});
// 開啟智能降噪
await rtcModule.setParameters({
			Cmd: 'SetAudioAiNoise',
			Enable: 1
		}, (res) => {
			console.log('私人定制', res);
		});
  • 采集音視頻
    如果是語音通話可以不執行下列代碼
// 設置視頻編碼屬性
await rtcModule.setVideoEncoderConfiguration({},res) => {
console.log('RTC 設置視頻編碼屬性 setVideoEncoderConfiguration 方法調用', res.code ===0 ? '成功' :'失敗:' + res);
});
// 啟用視頻
await rtcModule.enableVideo((res) => {
console.log('RTC 啟用視頻 enableVideo 方法調用', res.code === 0 ? '成功' : '失敗:' +res);
});
  • 加入房間
rtcModule.joinChannel({
			"token": '',
			"channelId": 本地創建的頻道/通過呼叫邀請傳遞過來的頻道,
			"uid": 本地的userid,
		}, (res) => {
			console.log('RTC joinChannel 方法調用', res.code === 0 ? '成功' : '失敗:' + res);
		});
  • 本地視頻渲染

    <AR-CanvasView ref="location" style="flex: 1;" />
    

    獲取容器

    // 請確保可以獲取到容器
    Store.location = this.$refs.location;
    console.log(Store.location);
    // 打印后 類似這種
    {
    	"ref": "68",
    	"type": "AR-CanvasView",
    	"attr": {
    		"@styleScope": "data-v-39c12bd0"
    	},
    	"style": {
    		"flex": "1"
    	}
    }
    
     // 渲染視頻
    	await Store.location.setupLocalVideo({
    		"renderMode": 1,
    		"channelId": 加入的頻道房間
    		"uid": 本地的userid
    		"mirrorMode": 0
    	}, (res) => {
    		console.log('渲染視頻', res);
    	});
    	// 本地預覽
    	await Store.location.startPreview((res) => {
    		console.log('本地預覽', res);
    	})
    
  • 遠端視頻渲染
    通過回調 onFirstRemoteVideoDecoded 獲取遠端用戶發布視頻
    Store.remote 與 Store.location 類似

    await Store.remote.setupRemoteVideo({
    		"renderMode": 1,
    		"channelId": 加入的頻道
    		"uid": res.uid
    		"mirrorMode": 0
    	}, (res) => {
    		console.log('渲染遠端視頻', res);
    	})
    	// 本地預覽
    	await Store.remote.startPreview((res) => {
    		console.log('遠端本地預覽', res);
    	})
    
  • 掛斷

    	// 銷毀實例
    		rtcModule.destroyRtc((res) => {
    			console.log("銷毀實例", res);
    		});
    

總結

當前邏輯基本實現呼叫邀請+通話
需要更詳細,更具體,更全面的代碼請前往 demo 源碼 地址

  • 注意事項
    • RTM 初始化、RTC 初始化都只需要執行一次,多次執行請殺掉程序
    • RTM 可以在 vue頁面, RTC 視頻容器必須在 nvue 頁面


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM