Speaking of which, this is not the first Time for me to come into contact with live streaming. From videoJS to flvJs, there are many wheels about live streaming on the Internet, and you can use them directly after studying the documents. Tencent Real-time Communication is used this Time. TRTC), make a note when you’re done.

TRTC profile

Tencent has launched two scenarios of multi-person audio and video call and low-delay interactive live broadcast, focusing on the interoperability of all platforms and providing SDK for small program, Web, Android, iOS, Electron, Windows, macOS and other platforms.

Official Product Architecture:

Basic functions: video call, voice call, interactive video live, interactive voice live.

The official documentation address: cloud.tencent.com/document/pr…

Access to the process

A completed video demo contains three files: trtC-room. WXML, trtC-room. js, trtC-wx.js:

  1. Trtc-room. WXML is a self-written WXML file that includes and nodes. The real-time audio and video of the small program is based on the label and implementation of wechat’s native components.

  2. Trtc-wx. js is a class that manages TRTC state for you, a pure JS module that manages all states related to real-time audio and video, and calls methods mounted on and.

  3. Trtc-room. js is the business layer code, referencing trtC-wx.js

Access to

  1. Register Tencent cloud account and complete real-name authentication.
  2. Create a new application, the official documentation guidelines: cloud.tencent.com/document/pr… Download demo. Modify the configuration parameters

3. Run Demo in the local browser and obtain SDKAPPID, userID, userSig, and roomID.

TRTC – room. Js

  1. The introduction of
/ / NPM installation
npm install trtc-wx-sdk

// Local import
import TRTC from './utils/trtc-wx.js'
Copy the code
  1. Initialize the TRTC binding event
OnLoad (){this.trtc = new TRTC(this) // pusherConfig = {beautyLevel: 9, cloudenv: "DEV",} this.setdata ({pusher: this.trtc.createpusher (pusherConfig).pusherattributes}) // bindEvent this.bindevent (); }Copy the code
  1. Enter the room to publish the local stream
    this.setData({
      pusher: this.TRTC.enterRoom(this.data.trtcConfig),
    }, () = > {
      // Start pushing flow
      this.TRTC.getPusherInstance().start({
        success: function (event) {
          console.log("Push stream successful --------", event)
        },
        fail: function (err) {
          console.log("Push stream failed --------", err)
        }
      }) 
    })
Copy the code
  1. Listen for remote users to enter the room and subscribe to remote streams
This.trtc. on(event.remote_user_Join, this.onremoteJoin, This) // Listen for the remote video stream to add this.trtc.on (event.remote_video_add, This.onremotechange,this) // Listen for the remote audio stream to add this.trtc.on (event.remote_video_remove, this.onremotechange,this)Copy the code
  1. Check out and reset all status
 const result = this.TRTC.exitRoom()
 this.setData({
      pusher: result.pusher,
      playerList: result.playerList,
 })
Copy the code
  1. Complete demo
<view class="template-1v1">
    <view wx:for="{{streamList}}" wx:key="streamID" wx:if="{{item.src && (item.hasVideo || item.hasAudio)}}" class="view-container player-container {{item.isVisible? '':'none'}}">
      <live-player
        class="player"
        id="{{item.streamID}}"
        data-userid="{{item.userID}}"
        data-streamid="{{item.streamID}}"
        data-streamtype="{{item.streamType}}"
        src= "{{item.src}}"
        mode= "RTC"
        autoplay= "{{item.autoplay}}"
        mute-audio= "{{item.muteAudio}}"
        mute-video= "{{item.muteVideo}}"
        orientation= "{{item.orientation}}"
        object-fit= "{{item.objectFit}}"
        background-mute= "{{item.enableBackgroundMute}}"
        min-cache= "{{item.minCache}}"
        max-cache= "{{item.maxCache}}"
        sound-mode= "{{item.soundMode}}"
        enable-recv-message= "{{item.enableRecvMessage}}"
        auto-pause-if-navigate= "{{item.autoPauseIfNavigate}}"
        auto-pause-if-open-native= "{{item.autoPauseIfOpenNative}}"
        debug="{{debug}}"
        bindstatechange="_playerStateChange"
        bindfullscreenchange="_playerFullscreenChange"
        bindnetstatus="_playerNetStatus"
        bindaudiovolumenotify  ="_playerAudioVolumeNotify"
      />
    </view>
    <view class="view-container pusher-container {{pusher.isVisible? '':'none'}} {{streamList.length===0? 'fullscreen':''}}">
      <live-pusher
        class="pusher"
        url="{{pusher.url}}"
        mode="{{pusher.mode}}"
        autopush="{{pusher.autopush}}"
        enable-camera="{{pusher.enableCamera}}"
        enable-mic="{{pusher.enableMic}}"
        muted="{{! pusher.enableMic}}"
        enable-agc="{{pusher.enableAgc}}"
        enable-ans="{{pusher.enableAns}}"
        enable-ear-monitor="{{pusher.enableEarMonitor}}"
        auto-focus="{{pusher.enableAutoFocus}}"
        zoom="{{pusher.enableZoom}}"
        min-bitrate="{{pusher.minBitrate}}"
        max-bitrate="{{pusher.maxBitrate}}"
        video-width="{{pusher.videoWidth}}"
        video-height="{{pusher.videoHeight}}"
        beauty="{{pusher.beautyLevel}}"
        whiteness="{{pusher.whitenessLevel}}"
        orientation="{{pusher.videoOrientation}}"
        aspect="{{pusher.videoAspect}}"
        device-position="{{pusher.frontCamera}}"
        remote-mirror="{{pusher.enableRemoteMirror}}"
        local-mirror="{{pusher.localMirror}}"
        background-mute="{{pusher.enableBackgroundMute}}"
        audio-quality="{{pusher.audioQuality}}"
        audio-volume-type="{{pusher.audioVolumeType}}"
        audio-reverb-type="{{pusher.audioReverbType}}"
        waiting-image="{{pusher.waitingImage}}"
        debug="{{debug}}"
        bindstatechange="_pusherStateChangeHandler"
        bindnetstatus="_pusherNetStatusHandler"
        binderror="_pusherErrorHandler"
        bindbgmstart="_pusherBGMStartHandler"
        bindbgmprogress="_pusherBGMProgressHandler"
        bindbgmcomplete="_pusherBGMCompleteHandler"
        bindaudiovolumenotify="_pusherAudioVolumeNotify"
      />
      <view class="loading" wx:if="{{streamList.length === 0 && ! isConnectioned}}">
        <view class="loading-img">
          <image src="./static/loading.png" class="rotate-img"></image>
        </view>
        <view class="loading-text">Wait for...</view>
      </view>
    </view>
    <view class="bottom-btns">
      <view class="btn-hangup" bindtap="_hangUp">
        <image class="btn-image" src="./static/hangup.png"></image>
      </view>
      <view class="btn-normal" bindtap="_switchCamera" >
        <image class="btn-image" src="./static/switch.png"></image>
      </view>
    </view> 
  </view>
Copy the code

//trtc.js
import TRTC from "./utils/trtc-wx"
const TAG_NAME = 'TRTC-ROOM'
Page({

  /** * initial data for the page */
  data: {
    pusher: null.streamList: [].// Used to render the player list and store Stram
    debug: false.// Whether to enable player pusher debugging
    cameraPosition: ' '.// Camera position, used for debug
    trtcConfig: {sdkAppID: '1400573664'.// Enable the real-time audio and video service SDKAppID assigned after the application is created
      userID: 'user_55273738'.// User ID, which can be specified by your account system
      userSig: 'eJwtzM0KgkAUBeB3ma2ht-kVoUWCmBWzsFzoRoKZ7BKJqIkUvXuiLs93DudLrueLO9iWBIS6QDZzRmPrHu8487uzbSkEVUwxfx105nlrGjQk2HIAoZiUfGl 6fNlJJeO*EsDponZssJ1cAvcB1g*spvdE6-HBjmky7NOQO8lBx3HUFae8CPXHM5HNM0-WmFUO7MjvD-psMbc_'.// The identity signature is equivalent to the login password
      template: '1v1'.// Screen layout mode
      roomID: '24193'./ / room number
      debugMode: false.enableMic: true.enableCamera: true,}},/** * lifecycle function -- listens for page loading */
  onLoad: function (options) {
    // Set the screen to steady on
    wx.setKeepScreenOn({
      keepScreenOn: true,})this.TRTC = new TRTC(this);
  
    / / create the pusher
    this.createPusher();
    // Bind events
    this.bindEvent();
    // Initialize the page state
    this.initStatus();
    // Enter the room
    this.enterRoom()
  },
  / * * *@description: Data initialization *@return: void
   */
  createPusher(){
    // pusher initialization parameters
    const pusherConfig = {
      beautyLevel: 9.cloudenv: "DEV",}const pusher = this.TRTC.createPusher(pusherConfig)
    this.setData({
      pusher: pusher.pusherAttributes,
    })
  },
  / * * *@description: Publish local streams, subscribe to events. Enter the room@return: void
   */
  enterRoom: function () {
    if (!this.checkParam(this.data.trtcConfig)) {
      console.log('checkParam false: missing necessary parameter, entered room not executed ')
      return
    }
    this.setData({
      pusher: this.TRTC.enterRoom(this.data.trtcConfig),
    }, () = > {
      // Start pushing flow
      this.TRTC.getPusherInstance().start({
        success: function (event) {
          console.log("Push stream successful --------", event)
        },
        fail: function (err) {
          console.log("Push stream failed --------", err)
        }
      }) 
      this.status.isPush = true; })},/ * * *@description: Check out, stop pushing and pulling, and reset data *@return: void
    */
  exitRoom(){
    const result = this.TRTC.exitRoom()
    this.setData({
        pusher: result.pusher,
        streamList: result.playerList,
    })
  },
  / * * *@description: Initializes page state *@return: void
   */
  initStatus() {
    this.status = {
      isPush: false.// Push flow state
      isPending: false.// Suspend state, 5000 event is marked as true and false after onShow}},/ * * *@description: Bind event listens for TRTC status *@return: void
    */
  bindEvent(){
    const EVENT = this.TRTC.EVENT;
    // The local user enters the room
    this.TRTC.on(EVENT.LOCAL_JOIN, this.onLocalJoin, this);
    // The local user leaves
    this.TRTC.on(EVENT.LOCAL_LEAVE, this.onLocalLeave, this);
    // The remote user enters the room
    this.TRTC.on(EVENT.REMOTE_USER_JOIN, this.onRemoteJoin, this)
    // The remote user leaves
    this.TRTC.on(EVENT.REMOTE_USER_LEAVE, this.onRemoteLeave, this)
    // The video state is true
    this.TRTC.on(EVENT.REMOTE_VIDEO_ADD, this.onRemoteChange,this)
    // Video status false
    this.TRTC.on(EVENT.REMOTE_VIDEO_REMOVE, this.onRemoteChange, this)
    // Audio is available
    this.TRTC.on(EVENT.REMOTE_AUDIO_ADD, this.onRemoteChange, this)
    // Audio is not available
    this.TRTC.on(EVENT.REMOTE_AUDIO_REMOVE, this.onRemoteChange, this)
    // Error handling
    this.TRTC.on(EVENT.ERROR, this.onTrtrError)
    // The status of the local push network changed
    this.TRTC.on(EVENT.LOCAL_NET_STATE_UPDATE, this.onLocalNetStateChange)
    // The status of the remote push network changed
    this.TRTC.on(EVENT.REMOTE_NET_STATE_UPDATE, this.onRemoteNetStateUpdate)
  },
  / * * *@description: TRTC event listening binding function *@param {*} event 
   * @return: void
   */
  onRemoteJoin(event){
    this.log("Remote user enters the room", event)
    const { data } = event;
    const { playerList } = data;
    this.setData({
      streamList: playerList,
    }, () = > {
      // The service is connected})},onRemoteLeave(event){
    this.log("Remote User Leaves", event)
    const { data, eventCode } = event;
    const { playerList, userID } = data;
    const _this = this;
    if (userID) {
      this.setList({
        streamList: playerList
      }).then(() = > {
        // Execute the user exit logic})}},onRemoteChange(event){
    const { data, eventCode } = event;
    const { player } = data;
    let option = {}
    switch (eventCode) {
      case "REMOTE_AUDIO_REMOVE":
        Object.assign(option, { muteAudio: true })
        this.log("Remote audio removal", event)
        break;
      case "REMOTE_AUDIO_ADD":
        Object.assign(option, { muteAudio: false })
        this.log("Remote audio available", event)
        break;
      case "REMOTE_VIDEO_REMOVE":
        Object.assign(option, { muteVideo: true })
        this.log("Remote Video Removal", event)
        break; 
      case "REMOTE_VIDEO_ADD":
        Object.assign(option, { muteVideo: false })
        this.log("Remote video available", event)
        break; 
    }
    this.setPlayerAttributesHandler(player, option)
  },
  onLocalJoin(event){
    this.log("Local User Enters the room", event)
  },
  onLocalLeave(event){
    this.log("Local User Leaving", event)
  },
  onTrtrError(event){
    this.log("Trtr Error", event)
  },
  onLocalNetStateChange(event){
    this.log("Local Network Changes", event)
    const pusher = event.data.pusher
    this.setData({
      pusher: pusher
    })
  },
  onRemoteNetStateUpdate(event){
    this.log("Remote Network Changes", event)
    const { playerList } = event.data;
    this.setData({
      streamList: playerList
    })
  },
  / * * *@description Set a player property *@param {*} player 
   * @param {*} options { muteAudio: true/false , muteVideo: true/false }
   * @return: void
   */
  setPlayerAttributesHandler(player, options) {
    this.setData({
      streamList: this.TRTC.setPlayerAttributes(player.streamID, options),
    })
  },
  / * * *@description Switch front and rear cameras */
  _switchCamera() {
    if (!this.data.cameraPosition) {
      . / / this data. The pusher. CameraPosition is the initial value, does not support dynamic Settings
      this.data.cameraPosition = this.data.pusher.frontCamera
    }
    console.log(TAG_NAME, 'switchCamera'.this.data.cameraPosition)
    this.data.cameraPosition = this.data.cameraPosition === 'front' ? 'back' : 'front'
    this.setData({
      cameraPosition: this.data.cameraPosition,
    }, () = > {
      console.log(TAG_NAME, 'switchCamera success'.this.data.cameraPosition)
    })
    // WX 7.0.9 does not support dynamic setting of pusher.frontCamera, only supports API switchCamer() setting, here modify cameraPosition to record state
    this.TRTC.getPusherInstance().switchCamera() 
  },
  / * * *@description Click the Hang up button to exit the call */
  _hangUp() {
    let _this = this;
    setTimeout(() = > {
      _this.exitRoom();
    }, 1000);
  },
  / * * *@description Set the list data and trigger page rendering *@param {Object} params include  stramList
   * @returns {Promise}* /
  setList(params) {
    console.log(TAG_NAME, 'setList', params, this.data.template)
    const { streamList } = params
    return new Promise((resolve, reject) = > {
      const data = {
        streamList: streamList || this.data.streamList,
      }
      this.setData(data, () = > {
        resolve(params)
      })
    })
  },
  / * * *@description TRTC Initialization Room This parameter is mandatory. Check *@param {Object} RtcConfig RTC parameter *@returns {Boolean}* /
  checkParam(rtcConfig) {
    console.log(TAG_NAME, 'checkParam config:', rtcConfig)
    if(! rtcConfig.sdkAppID) {console.error('sdkAppID not set')
      return false
    }
    if (rtcConfig.roomID === undefined) {
      console.error('roomID not set')
      return false
    }
    if (rtcConfig.roomID < 1 || rtcConfig.roomID > 4294967296) {
      console.error('roomID out of range 1 to 4294967295')
      return false
    }
    if(! rtcConfig.userID) {console.error('userID not set')
      return false
    }
    if(! rtcConfig.userSig) {console.error('userSig not set')
      return false
    }
    if(! rtcConfig.template) {console.error('Template not set')
      return false
    }
    return true
  },
  / * * *@description pusher event handler
   * @param {*} Event Indicates the event instance */
  _pusherStateChangeHandler(event) {
    console.log(event, "pusherEventHandler")
    this.TRTC.pusherEventHandler(event)
    const code = event.detail.code
    const message = event.detail.message
    switch (code) {
        case 5000:
          console.log(TAG_NAME, 'Applet suspended:', code)
          break
        case 5001:
          // 20200421 Only Android wechat will trigger this event
          console.log(TAG_NAME, 'Small program hover window is closed:', code)
          console.log(this.status.isPush, "this.status.isPush")
          this.status.isPending = true
          if (this.status.isPush) {
              this.exitRoom()
          }
          break}},_pusherNetStatusHandler(event) {
    this.warnLog('NetStatus', event)
    this.TRTC.pusherNetStatusHandler(event)
  },
  _pusherErrorHandler(event) {
    this.warnLog('pusherErro', event)
    this.TRTC.pusherErrorHandler(event)
  },
  _pusherBGMStartHandler(event) {
    this.warnLog('pusherBGMStart', event)
    this.TRTC.pusherBGMStartHandler(event)
  },
  _pusherBGMProgressHandler(event) {
    this.warnLog('BGMProgress', event)
    this.TRTC.pusherBGMProgressHandler(event)
  },
  _pusherBGMCompleteHandler(event) {
    this.warnLog('BGMComplete', event)
    this.TRTC.pusherBGMCompleteHandler(event)
  },
  _pusherAudioVolumeNotify(event) {
    this.warnLog('AudioVolume', event)
    this.TRTC.pusherAudioVolumeNotify(event)
  },
  _playerStateChange(event) {
    this.warnLog('playerStateChange', event)
    this.TRTC.playerEventHandler(event)
  },
  _playerFullscreenChange(event) {
    this.warnLog('Fullscreen', event)
    this.TRTC.playerFullscreenChange(event)
  },
  _playerNetStatus(event) {
    this.warnLog('playerNetStatus', event)
    this.TRTC.playerNetStatus(event)
  },
  _playerAudioVolumeNotify(event) {
    this.warnLog('playerAudioVolume', event)
    this.TRTC.playerAudioVolumeNotify(event)
  },
  / * * *@description The console. * warn method@param {*} msg: message detail string
   * @param {*} event : event object
   */
  warnLog (msg, event) {
    console.warn(TAG_NAME, msg, event)
  },
  / * * *@description The console. * log method@param {*} msg: message detail string
   * @param {*} event : event object
   * @return: void
   */
  log(msg, event){
    console.log(TAG_NAME, msg, event)
  },
})
Copy the code
  1. Points to be aware of
  • Applet background needs to open applet category and push and pull flow label permission. TRTC launched by Tencent is also based on push and pull stream, so it also needs permissions. This requires an enterprise number to apply

  • Tests need to be debugged on a real machine, and developer tools do not support push stream tabs.