写点什么

web 技术分享| React 版本 anyRTC 示例对等连接

发布于: 刚刚

前言

大家好,笔者以往发布过很多关于 WebRTC 的知识,和很多基于 anyRTC WebSDK 开发的音视频通讯示例,收获了很多开发人员的一致好评,在以往的示例中笔者是基于 Vue 框架进行编写,后台有小伙伴私信笔者,希望笔者出一个基于 React 框架的音视频示例,笔者在收到私信的第一时间就开始着手编写,现在把它发布出来供大家参考。

开发准备

在开始写代码之前还需要做一些准备工作,如果你之前没有使用过 anyRTC Web SDK 这里还需要花几分钟时间准备一下, 详见:开发前期准备

创建 React 程序

  • 全局安装


npm install -g create-react-app
复制代码


  • 通过 create-react-app 项目名称(注:项目名称不能有大写)


create-react-app peerconnection
复制代码

下载并引入项目依赖

npm install ar-rtc-sdk@4.1.3 -S
复制代码


  • 在 App.js 文件中引入


import React, { Component } from 'react';import ArRTC from 'ar-rtc-sdk';import Config from '../anyrtc_config';import './App.css';
复制代码

定义初始 state 数据

export default class App extends Component {    state = {        channel: '',        isLogin: false,        rtcClient: null,        videoDevices: null,        audioDevices: null,        audioTrack: null,        videoTrack: null,        list: []    }}
复制代码

创建 rtcClient 对象


componentDidMount() {    this.createRtcClient();}
createRtcClient = () => { const config = { mode: "rtc", codec: "h264" }; const rtcClient = ArRTC.createClient(config); // 更新state后,开始监听远端用户发布和取消发布音视频 this.setState({ rtcClient }, () => { this.listenUserPublished(); this.listenUserUnpublished(); });}
复制代码

监听远端用户发布和取消发布音视频

  • user-published 该回调通知远端用户发布了新的音频轨道或者视频轨道,你可以在该回调中订阅并播放远端用户的音视频轨道。详见 subscribeRemoteTrack.play

  • user-unpublishe 该回调通知远端用户取消发布了音频或视频轨道。


listenUserUnpublished = () => {    const { rtcClient, list } = this.state;    rtcClient.on("user-unpublished", async (user, mediaType) => {        if (mediaType === 'video') {            const index = list.findIndex(item => item.uid === user.uid);            if (index !== -1) {                list.splice(index, 1);                this.setState({ list });            }        }    });};
listenUserPublished = () => { const { rtcClient, list } = this.state; rtcClient.on("user-published", async (user, mediaType) => { await rtcClient.subscribe(user, mediaType); if (mediaType === 'video') { list.push(user); this.setState({ list }, () => { user.videoTrack.play('distal' + user.uid); }); } else if (mediaType === 'audio') { user.audioTrack.play(); } });}
复制代码

加入频道


join = () => {    const { rtcClient, channel } = this.state;    const { appid, uid } = Config;        rtcClient.join(appid, channel, null, uid).then((uid) => {        this.setState({ isLogin: true }, async () => {            await this.getDevices();            await this.createTrack();            const { videoTrack, audioTrack } = this.state;            videoTrack && videoTrack.play('local');            audioTrack && rtcClient.publish(audioTrack);            videoTrack && rtcClient.publish(videoTrack);        });    }).catch(e => {        alert('加入频道失败');    });}
复制代码

获取本地摄像头和麦克风并创建音视频轨道


getDevices = async () => {    const [ videoDevices, audioDevices ] = await Promise.all([        ArRTC.getCameras(),        ArRTC.getMicrophones(),    ]);    this.setState({        videoDevices,        audioDevices    });}
createTrack = async () => { this.setState({ audioTrack: await ArRTC.createMicrophoneAudioTrack() }); if (this.state.videoDevices?.length) { this.setState({ videoTrack: await ArRTC.createCameraVideoTrack() }); }}
复制代码

挂断离开


hangUp = () => {    const { videoTrack, rtcClient } = this.state;    videoTrack && videoTrack.stop();    rtcClient.leave();    this.setState({         channel: '',        isLogin: false,        videoDevices: null,        audioDevices: null,        audioTrack: null,        videoTrack: null    });}
复制代码

获取频道输入框的值

channelInputChange = (e) => {    this.setState({        channel: e.target.value    });}
复制代码

render 函数

render() {    const { isLogin, channel, list } = this.state;    return (        <div id='container'>            <div className='title'>                <a href="https://www.anyrtc.io/" target='_blank'>anyRTC samples</a>                 <span>Peer connection</span>            </div>            <div className='instructions'>The local user id is <span className='userId'>{ Config.uid }</span></div>            <div id='playContainer'>                { isLogin && <div id='local'></div> }                { isLogin && list.map((user) => {                    return (<div id={ 'distal' + user.uid } className='distal'></div>)                }) }            </div>            { isLogin && <button onClick={ this.hangUp } className='btn'>Hang Up</button> }            { !isLogin && <input type="text" value={ channel } ref={ this.channelInput } onChange={ this.channelInputChange } className='channelInput' placeholder='Please enter the channel'/> }            { !isLogin && <button onClick={ this.join } disabled={ !channel } className='joinBtn'>join</button> }            <div className='instructions'>View the console to see logging. The MediaStream object localStream, and the RTCPeerConnection objects pc1 and pc2 are in global scope, so you can inspect them in the console as well.</div>            <div className='instructions'>For more information about anyRTC WebRTC, see Getting Started With <a href="https://docs.anyrtc.io/cn/Video/api-ref/rtc_web/overview" target='_blank'>anyRTC</a></div>            <a href="https://github.com/941725931/webRTC_React" id="viewSource" target='_blank'>View source on GitHub</a>        </div>    );}
复制代码

CSS

#container {    margin: 0 auto 0 auto;    max-width: 60em;    padding: 1em 1.5em 1.3em 1.5em;}
.title { border-bottom: 1px solid #ccc; margin: 0 0 0.8em 0; padding: 0 0 0.2em 0; font-family: 'Roboto', sans-serif; font-weight: 500; font-size: 2em; white-space: nowrap;}
.title a, .instructions a { text-decoration: none; margin-right: 10px; color: #1D6EEE;}
.title a:hover { border-bottom: 2px solid #1D6EEE;}
.instructions { margin: 0.8em 0; font-family: 'Roboto', sans-serif; color: #444; font-weight: 300;}
.instructions .userId { color: #1D6EEE;}
#playContainer { display: flex; align-items: center;}
#local, .distal { width: 400px; height: 220px; margin-right: 20px; background-color: #222222;}
.btn { width: 70px; margin-top: 10px; line-height: 26px; text-align: center; color: #fff; background-color: #409EFF; border: none; border-radius: 2px; cursor: pointer; transition: .1s;}
.btn:active { transform: translateY(2px);}
.channelInput { width: 240px; height: 32px; border-radius: 4px; border: 1px solid #409EFF; outline: none; text-indent: .5rem; margin-right: 10px;}
.joinBtn { width: 80px; line-height: 34px; text-align: center; color: #fff; background-color: #409EFF; border: none; border-radius: 4px; cursor: pointer; transition: .1s;}
.joinBtn:active { transform: translateY(2px);}
.joinBtn[disabled] { background-color: #E1E1E2; cursor: not-allowed;}
#viewSource { display: block; margin: 1.3em 0 0 0; border-top: 1px solid #999; padding: 1em 0 0 0; color: #1D6EEE; font-weight: 300; text-decoration: none;}
#viewSource:hover, .instructions a:hover { text-decoration: underline;}
复制代码

运行效果和示例代码


感兴趣的小伙伴可以下载源码 github



发布于: 刚刚阅读数: 2
用户头像

实时交互,万物互联! 2020.08.10 加入

实时交互,万物互联,全球实时互动云服务商领跑者!

评论

发布
暂无评论
web技术分享| React版本 anyRTC示例对等连接