簡體   English   中英

WEBRTC,如果用戶 A 與用戶 B 建立連接。具有不同的視頻和音頻約束

[英]WEBRTC, establish connection if user A to user B. With different Video and Audio constraints

此代碼正在處理新用戶連接。

用戶 Class

class User{
  
  constructor(friendID){
    this.friendID = friendID;
    this.userName = null;
    this.myPeer = new RTCPeerConnection(servers);
    this.videoManager = new VideoManager();
    this.setup_events();
  }

  get name(){
    return this.userName;
  }

  get id(){
    return this.friendID;
  }

  setup_events(){ 

    let this_instance = this;

    this.myPeer.onicecandidate = function(event){ 
      if (event.candidate !== null){
        LOG("ICE CANDIDATE SEND TO " + this_instance.friendID);
        LOG_obj(event.candidate);
        socket.emit("ice-candidate", event.candidate, this_instance.friendID);
      }else{
        LOG("EMPTY CANDIDATE");
      }
    }
    this.myPeer.addEventListener('track', async(event) => {
      const [remoteStream] = event.streams;
      this_instance.videoManager.createVideo();
      this_instance.videoManager.setStream(remoteStream);
      LOG("ADDED stream to VideoObject");
    });
  }

  add_candidate(candidate){
    this.myPeer.addIceCandidate( new RTCIceCandidate(candidate) );
    LOG("CANDIDATE ADDED TO PEER");
  } 

  accept_offer(userOffer){
    this.myPeer.setRemoteDescription(new RTCSessionDescription(userOffer));
    LOG("ACCEPTED OFFER");
  }

  async create_offer(){

    MediaRules.get_MediaRules()
      .then( (mediaRules) => {

        navigator.mediaDevices.getUserMedia(mediaRules).then( (mediaStream) =>{
          let tracks = mediaStream.getTracks();

          tracks.forEach( track => { this.myPeer.addTrack(track, mediaStream); });

          LOG("ADDED ALL TRACKS");
        }).then( () => {
            this.myPeer.createOffer(mediaRules).then( (offerObj) => {
              
              this.myPeer.setLocalDescription(offerObj);
              socket.emit("user-offer", offerObj, this.friendID);
        });
      });
  });
  }

  accept_answer(userAnswer){
    this.myPeer.setRemoteDescription(new RTCSessionDescription(userAnswer));
    LOG("ACCEPTED ANSWER");
  }

  async create_answer(){

    MediaRules.get_MediaRules().then( (mediaRules) => {
      
      navigator.mediaDevices.getUserMedia(mediaRules).then( (mediaStream) => {
        let tracks = mediaStream.getTracks();
        tracks.forEach( track => { this.myPeer.addTrack(track, mediaStream); });
        LOG("ADDED ALL TRACKS");
      }).then( () => {
          this.myPeer.createAnswer(mediaRules).then( (answerObj) => {
            this.myPeer.setLocalDescription(answerObj); 
            socket.emit("user-answer", answerObj, this.friendID);
          });
        });
    });
  }
}

用戶池

class UsersPool{
  
  constructor(){
    this.UsersMap = {};
  }

  addUser(userObj){
    this.UsersMap[userObj.id] = userObj;
  }

  accept_IceCandidate(candidateObject, user_id){
    this.UsersMap[user_id].add_candidate(candidateObject);
  }

  accept_Offer(offerObject, user_id){
    LOG("ACCEPT OFFER FROM " + user_id);
    this.UsersMap[user_id].accept_offer(offerObject);
  }

  accept_Answer(answerObject, user_id){
    this.UsersMap[user_id].accept_answer(answerObject);
  }

  async CreateSendOffer(user_id){
    await this.UsersMap[user_id].create_offer();
  }

  async CreateSendAnswer(user_id){
    await this.UsersMap[user_id].create_answer();
  }
}

媒體限制

class MediaConstraints{

  async get_MediaRules(){
    let mediaRules = { video: false, audio: false };

    let devicesEnum = await navigator.mediaDevices.enumerateDevices();

    devicesEnum.forEach( device => {
      if ( device.kind == "audioinput" ){
        mediaRules["audio"] = true;
      }
      else if ( device.kind == "videoinput"){
        mediaRules["video"] = true;
      }
    });
    return mediaRules;
  }
}

視頻管理器(由用戶創建視頻元素)

class VideoManager {

  constructor(){
    this.videoObject = null;
  }

  createVideo(){
    let videoObject = document.createElement("video");
    let divVideo = document.createElement("div");

    videoObject.setAttribute('width', "600");
    videoObject.setAttribute('height', "800");

    divVideo.appendChild(videoObject); 

    document.body.appendChild(divVideo);

    this.videoObject = videoObject;
  }

  setStream(stream){
    this.videoObject.srcObject = stream; 
    this.videoObject.play();
  }
}

嗯,問題就在這里。 icecandidate 運行良好,信令服務器也運行良好。 TURN/STUN 服務器工作正常。

我的主要問題是如何創建約束並正確設置如果用戶 A 沒有網絡攝像頭但用戶 B 有,則提供和回答。 目前我收到 STUN 服務器已損壞的錯誤,但這是因為對等方無法完成彼此之間的連接建立。

如何制作,如果我的筆記本電腦上只有麥克風,但在其他筆記本電腦上我有視頻和麥克風。

編輯 0:嗯,看起來 WebRTC 不喜歡如果約束不同,如果用戶 A 使用 {video: false, audio: true} 創建報價,並將其發送給用戶 B,而用戶 B 使用 {video: true 創建答案, audio: true} 然后連接失敗,因為約束不同。

仍然不明白為什么這是一個問題。

編輯 1:看起來唯一的方法是使用 addTransceiver 並手動控制媒體。

嗯,這很有趣。

問題出在 Firefox (107.0 x64) 和 Google Chrome 瀏覽器中 Debian 11 Bullseye。

我不知道到底是什么問題,但使用其他操作系統,如 Windows 和 MacOS。 一切正常。

編輯:我沒有解決問題,在 linux 上這個問題仍然存在。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM