欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > WebRTC音视频开发读书笔记(五)

WebRTC音视频开发读书笔记(五)

2025/2/25 23:22:14 来源:https://blog.csdn.net/ch_s_t/article/details/141291847  浏览:    关键词:WebRTC音视频开发读书笔记(五)

WebRTC既可以收发音频和视频,还可以传输其它数据,如短消息、二进制数据、文本数据等。可以实现文本聊天、文件传输等场景。

八、数据通道

1、基本概念

WebRTC的数据通道好比高速公路、文本、文件、图像以及其它数据 好比货物,通道打通 ,即可源源不断地发送数据。数据通道的创建依赖于RTCPeerConnection连接建立,数据通道相关API:

RTCDataChannel通信与WebSocket通信之间区别:

(1)WebRTCDataChannel通信基于Peer与Peer之间直接连接,WebSocket通信需要服务器中转,但WebRTC依靠ICE Servers穿透NAT,有时可能多一层TURN服务器的转发。

(2)WebSocket协议是基于TCP传输,RTCDataChannel是基于SCTP(同TCP 、UDP同级的传输协议)

 (3)构造WebSocket需要一个URL,与服务器建立连接,创建一个唯一的SocketSessionId。DataChannel的连接依赖RTCPeerConnection 对象,可以包含多个RTCDataChannel。

2、文本传输示例

数据通道最基本应用场景是发送文本消息,使RTCPeerConnection的createData-Channel方法创建一个可以发送任意数据的数据通道,创建时需要传递一个字符串作为通道id。通道建立后,发送端通过 send方法发送消息,接收端连接通过监听ondatachannel事件,可以获取远端数据通道,此时远端数据通道监听onmessage事件,就可以接收文本消息。以下是一个发送的文本的示例,主体步骤如下:

主体步骤:

(1)创建本地/远端连接,发送/接收数据通道。如下所示:

                本地连接对象:localConnection

                远端连接对象: remoteConnection

                        发送通道: sendChannel

                        接收通道: receiveChannel 

   (2)   建立本地及远端连接

 (3)实例化本地发送数据通道,并指定通道id,然后添加onopen及onclose事件监听。大致代码如下:

sendChannel=localConnection.createDataChannel('webrtc-datachannel')sendChannel.onpen={...}sendChannel.onclose{...}

(4)在远端连接里添加ondatachannel事件,然后拉收端数据通道receiveChannel再添加onmessage事件,用于接收发送端发过来的文本消息.

remoteConnection.ondatachannel=(event){receiveChannel=event.channel;//接收事件监听receiveChannel.onmessage=(event){//消息event.data}receiveChannel.onopen={...}receiveChannel.oclose={...}
}

(5) 在界面渲染部分添加两个文本框,一个用于输入发送的内容,一个用于接收文本消息,通过调用dataChannel的send方法将数据发送出去,

完整代码如下:

import React from "react";
import { Button } from "antd";
import '../public/dataChannel.css'//本地连接对象
let localConnection;
//远端连接对象
let remoteConnection;
//发送通道
let sendChannel;
//接收通道
let receiveChannel;
/*** 数据通道示例*/
class DataChannel extends React.Component {//呼叫call = async () => {console.log('开始呼叫...');//设置ICE Server,使用Google服务器let configuration = { "iceServers": [{ "url": "stun:stun.l.google.com:19302" }] };//创建RTCPeerConnection对象localConnection = new RTCPeerConnection(configuration);console.log('创建本地PeerConnection成功:localConnection');//监听返回的Candidate信息localConnection.addEventListener('icecandidate', this.onLocalIceCandidate);//实例化发送通道sendChannel = localConnection.createDataChannel('webrtc-datachannel');//onopen事件监听sendChannel.onopen = this.onSendChannelStateChange;//onclose事件监听sendChannel.onclose = this.onSendChannelStateChange;//创建RTCPeerConnection对象remoteConnection = new RTCPeerConnection(configuration);console.log('创建本地PeerConnection成功:remoteConnection');//监听返回的Candidate信息remoteConnection.addEventListener('icecandidate', this.onRemoteIceCandidate);//远端连接数据到达事件监听remoteConnection.ondatachannel = this.receiveChannelCallback;//监听ICE状态变化localConnection.addEventListener('iceconnectionstatechange', this.onLocalIceStateChange);//监听ICE状态变化remoteConnection.addEventListener('iceconnectionstatechange', this.onRemoteIceStateChange);try {console.log('localConnection创建提议Offer开始');//创建提议Offerconst offer = await localConnection.createOffer();//创建Offer成功await this.onCreateOfferSuccess(offer);} catch (e) {//创建Offer失败this.onCreateSessionDescriptionError(e);}}//创建会话描述错误onCreateSessionDescriptionError = (error) => {console.log(`创建会话描述SD错误: ${error.toString()}`);}//创建提议Offer成功onCreateOfferSuccess = async (desc) => {//localConnection创建Offer返回的SDP信息console.log(`localConnection创建Offer返回的SDP信息\n${desc.sdp}`);console.log('设置localConnection的本地描述start');try {//设置localConnection的本地描述await localConnection.setLocalDescription(desc);this.onSetLocalSuccess(localConnection);} catch (e) {this.onSetSessionDescriptionError();}console.log('remoteConnection开始设置远端描述');try {//设置remoteConnection的远端描述await remoteConnection.setRemoteDescription(desc);this.onSetRemoteSuccess(remoteConnection);} catch (e) {//创建会话描述错误this.onSetSessionDescriptionError();}console.log('remoteConnection开始创建应答Answer');try {//创建应答Answerconst answer = await remoteConnection.createAnswer();//创建应答成功await this.onCreateAnswerSuccess(answer);} catch (e) {//创建会话描述错误this.onCreateSessionDescriptionError(e);}}//设置本地描述完成onSetLocalSuccess = (pc) => {console.log(`${this.getName(pc)}设置本地描述完成:setLocalDescription`);}//设置远端描述完成onSetRemoteSuccess = (pc) => {console.log(`${this.getName(pc)}设置远端描述完成:setRemoteDescription`);}//设置描述SD错误onSetSessionDescriptionError = (error) => {console.log(`设置描述SD错误: ${error.toString()}`);}getName = (pc) => {return (pc === localConnection) ? 'localConnection' : 'remoteConnection';}//创建应答成功onCreateAnswerSuccess = async (desc) => {//输出SDP信息console.log(`remoteConnection的应答Answer数据:\n${desc.sdp}`);console.log('remoteConnection设置本地描述开始:setLocalDescription');try {//设置remoteConnection的本地描述信息await remoteConnection.setLocalDescription(desc);this.onSetLocalSuccess(remoteConnection);} catch (e) {this.onSetSessionDescriptionError(e);}console.log('localConnection设置远端描述开始:setRemoteDescription');try {//设置localConnection的远端描述,即remoteConnection的应答信息await localConnection.setRemoteDescription(desc);this.onSetRemoteSuccess(localConnection);} catch (e) {this.onSetSessionDescriptionError(e);}}//Candidate事件回调方法onLocalIceCandidate = async (event) => {try {if (event.candidate) {//将会localConnection的Candidate添加至remoteConnection里await remoteConnection.addIceCandidate(event.candidate);this.onAddIceCandidateSuccess(remoteConnection);}} catch (e) {this.onAddIceCandidateError(remoteConnection, e);}console.log(`IceCandidate数据:\n${event.candidate ? event.candidate.candidate : '(null)'}`);}//Candidate事件回调方法onRemoteIceCandidate = async (event) => {try {if (event.candidate) {//将会remoteConnection的Candidate添加至localConnection里await localConnection.addIceCandidate(event.candidate);this.onAddIceCandidateSuccess(localConnection);}} catch (e) {this.onAddIceCandidateError(localConnection, e);}console.log(`IceCandidate数据:\n${event.candidate ? event.candidate.candidate : '(null)'}`);}//添加Candidate成功onAddIceCandidateSuccess = (pc) => {console.log(`${this.getName(pc)}添加IceCandidate成功`);}//添加Candidate失败onAddIceCandidateError = (pc, error) => {console.log(`${this.getName(pc)}添加IceCandidate失败: ${error.toString()}`);}//监听ICE状态变化事件回调方法onLocalIceStateChange = (event) => {console.log(`localConnection连接的ICE状态: ${localConnection.iceConnectionState}`);console.log('ICE状态改变事件: ', event);}//监听ICE状态变化事件回调方法onRemoteIceStateChange = (event) => {console.log(`remoteConnection连接的ICE状态: ${remoteConnection.iceConnectionState}`);console.log('ICE状态改变事件: ', event);}//断开连接hangup = () => {console.log('结束会话');//关闭localConnectionlocalConnection.close();//关闭remoteConnectionremoteConnection.close();//localConnection置为空localConnection = null;//remoteConnection置为空remoteConnection = null;}sendData = () => {let dataChannelSend =document.getElementById('dataChannelSend');const data = dataChannelSend.value;sendChannel.send(data);console.log('发送的数据:' + data);}//接收通道数据到达回调方法receiveChannelCallback = (event) => {console.log('Receive Channel Callback');//实例化接收通道receiveChannel = event.channel;//接收消息事件监听receiveChannel.onmessage = this.onReceiveMessageCallback;//onopen事件监听receiveChannel.onopen = this.onReceiveChannelStateChange;//onclose事件监听receiveChannel.onclose = this.onReceiveChannelStateChange;}//接收消息处理onReceiveMessageCallback = (event) => {console.log('接收的数据:' + event.data);let dataChannelReceive =document.getElementById('dataChannelReceive');dataChannelReceive.value = event.data;}//发送通道状态变化`onSendChannelStateChange = () => {const readyState = sendChannel.readyState;console.log('发送通道状态: ' + readyState);}//接收通道状态变化onReceiveChannelStateChange = () => {const readyState = receiveChannel.readyState;console.log('接收通道状态:' + readyState);}render() {return (<div className="container"><div><div><h2>发送</h2><textarea id="dataChannelSend" disabled={false}placeholder="请输入要发送的文本..." /></div><div><h2>接收</h2><textarea id="dataChannelReceive" disabled={false} /></div></div><div><Button onClick={this.call} style={{ marginRight: "10px" }}>呼叫</Button><Button onClick={this.sendData} style={{ marginRight: "10px" }}>发送</Button><Button onClick={this.hangup} style={{ marginRight: "10px" }}>挂断</Button></div></div>);}
}
//导出组件
export default DataChannel;

测试此例时,一定选单击"呼叫"按钮建立对等连接,然后才能发送消息.

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词