preface
Hello, I have published a lot of knowledge about WebRTC in the past and many audio and video communication examples developed based on anyRTC WebSDK, which have been highly praised by many developers. In the past examples, the author is based on Vue framework, and there is a private letter from a small partner in the background. I hope the author can give an audio and video example based on React framework, The author began to write the private letter as soon as he received it, and now publish it for your reference.
Development preparation
Before writing code, you need to make some preparations. If you haven't used anyRTC Web SDK before, you need to take a few minutes to prepare. See the following for details: Pre development preparation
Create React program
- Global installation
npm install -g create-react-app
- Project name through create react app (Note: project name cannot be capitalized)
create-react-app peerconnection
Download and introduce project dependencies
npm install ar-rtc-sdk@4.1.3 -S
- Import in App.js file
import React, { Component } from 'react'; import ArRTC from 'ar-rtc-sdk'; import Config from '../anyrtc_config'; import './App.css';
Define initial state data
export default class App extends Component { state = { channel: '', isLogin: false, rtcClient: null, videoDevices: null, audioDevices: null, audioTrack: null, videoTrack: null, list: [] } }
Create rtcClient object
- adopt ArRTC.createClient Create a new client object.
componentDidMount() { this.createRtcClient(); } createRtcClient = () => { const config = { mode: "rtc", codec: "h264" }; const rtcClient = ArRTC.createClient(config); // After updating the state, start listening to the remote user publishing and canceling the publishing of audio and video this.setState({ rtcClient }, () => { this.listenUserPublished(); this.listenUserUnpublished(); }); }
Monitor remote users to publish and unpublish audio and video
-
user-published This callback notifies the remote user that a new audio track or video track has been published. You can subscribe to and play the remote user's audio and video track in this callback. See details subscribe and RemoteTrack.play.
-
user-unpublishe This callback notifies the remote user that the audio or video track has been unpublished.
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 channel
- join This method allows users to join the call channel, and users in the same channel can talk to each other.
- When calling this method to join a channel, the local trigger will be triggered ArRTCClient.on("connection-state-change") Callback.
- After the user in the communication scenario and the anchor in the live broadcast scenario join the channel, the remote end will trigger ArRTCClient.on("user-joined") Callback.
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('Failed to join channel'); }); }
Get local cameras and microphones and create audio and video tracks
-
getCameras This method enumerates the available video input devices, such as cameras. After the call is successful, the SDK will pass MediaDeviceInfo Object returns the available video input devices.
-
getMicrophones This method enumerates the available audio input devices, such as microphones. After the call is successful, the SDK will pass MediaDeviceInfo Object returns the available audio input devices.
-
createMicrophoneAudioTrack Create an audio track from the audio collected by the microphone.
-
createCameraVideoTrack Create a video track from the video captured by the camera.
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() }); } }
Hang up and leave
- leave When this method is called to leave the channel, it will be triggered locally ArRTCClient.on("connection-state-change") Callback.
- After the user in the communication scenario and the anchor in the live broadcast scenario leave the channel, the remote end will trigger ArRTCClient.on("user-left") Callback.
hangUp = () => { const { videoTrack, rtcClient } = this.state; videoTrack && videoTrack.stop(); rtcClient.leave(); this.setState({ channel: '', isLogin: false, videoDevices: null, audioDevices: null, audioTrack: null, videoTrack: null }); }
Gets the value of the channel input box
channelInputChange = (e) => { this.setState({ channel: e.target.value }); }
render function
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; }
Running effect and sample code
Interested partners can download the source code github