Javascript RTPeerConnection未侦听远程端口的跟踪事件

Javascript RTPeerConnection未侦听远程端口的跟踪事件,javascript,angular,webrtc,Javascript,Angular,Webrtc,我正在尝试使用WebRTC在应用程序中实现视频调用。共享报价、答案和ice候选人后,对等方之间的连接正在成功建立 远程对等方正在发送曲目(视频、音频),但本地对等方(接收对等方)未列出远程对等方连接的曲目 向对等连接添加跟踪: const localStream = await window.navigator.mediaDevices.getUserMedia({video: true, audio: true}); localStream.getTracks().forEach(track

我正在尝试使用WebRTC在应用程序中实现视频调用。共享报价、答案和ice候选人后,对等方之间的连接正在成功建立

远程对等方正在发送曲目(视频、音频),但本地对等方(接收对等方)未列出远程对等方连接的曲目

向对等连接添加跟踪:

const localStream = await window.navigator.mediaDevices.getUserMedia({video: true, audio: true});
localStream.getTracks().forEach(track => {
    this.peerConnection.addTrack(track, localStream);
});
this.peerConnection.addEventListener('track', async (event) => {
          console.log("Remote video stream added to the video element...");
            remoteStream.addTrack(event.track);
        });
另一侧收听曲目事件:

const localStream = await window.navigator.mediaDevices.getUserMedia({video: true, audio: true});
localStream.getTracks().forEach(track => {
    this.peerConnection.addTrack(track, localStream);
});
this.peerConnection.addEventListener('track', async (event) => {
          console.log("Remote video stream added to the video element...");
            remoteStream.addTrack(event.track);
        });
  • 如何接收和显示远程对等的视频
  • 有没有办法检查RTPEERCONNECTION的流/轨道
  • 我们在应用程序中使用angular。以下是完整的JS代码:

  • 触发视频通话组件以提供通话
  • 监听视频通话提供和触发视频通话组件
  • 从'@angular/core'导入{Component,OnInit,Inject};
    从“@angular/material/DIALOG”导入{MAT_DIALOG_DATA};
    从'src/app/User/model/User'导入{User};
    从'@stomp/ng2 stompjs'导入{RxStompService};
    从“rxjs”导入{Subscription};
    从'src/app/login/service/login.service'导入{LoginService};
    从'src/app/chats/model/Chat'导入{Chat};
    从'src/app/chats/model/chat type'导入{ChatType};
    从“uuid”导入{v4作为uuidv4};
    从'src/app/crypto/service/crypto.service'导入{CryptoService};
    @组成部分({
    选择器:“应用程序视频呼叫”,
    templateUrl:'./video call.component.html',
    样式URL:['./video call.component.css']
    })
    导出类VideoCallComponent实现OnInit{
    当前用户:用户;
    friendUser:用户;
    订阅:订阅;
    peerConnection:RTCPeerConnection;
    提供:聊天;
    答:聊天;
    候选人:聊天;
    generatedIceCandidateCount=0;
    receivedIceCandidateCount=0;
    iceCandidates=新数组();
    建造师(
    私人登录服务:登录服务,
    @注入(MAT_DIALOG_DATA)公共数据:任意,
    私有stompService:RxStompService,
    私有加密服务:加密服务
    ) {
    this.currentUser=this.loginService.getCurrentUser();
    if(data.friendUser){
    this.friendUser=data.friendUser;
    const配置={'iceServers':[{'url':'stun:stun.l.google.com:19302'}]};
    this.peerConnection=新的RTCPeerConnection(配置);
    这是.startReceivingStreams();
    //在本地RTPeerConnection上侦听本地ICE候选者
    this.peerConnection.addEventListener('icecandidate',事件=>{
    if(事件候选){
    //console.log('ICE候选者生成',event.候选者);
    log(“Genrated候选者”++this.generatedecandidateCount);
    this.iceCandidates.push(event.candidate);
    //this.sendToSocket(this.createChat(null,ChatType.ICE_-CANDIDATE,{'iceCandidate':event.CANDIDATE}));
    }否则{
    log(“缓冲区中的候选项:”,this.generatedecandidateCount);
    this.iceCandidates.forEach((candidate)=>{
    this.sendToSocket(this.createChat(null,ChatType.ICE_-CANDIDATE,{'iceCandidate':CANDIDATE}))
    });    
    如果(此.ICE.length>0)
    this.startTransmittingStreams();
    }
    });
    //侦听本地RTPeerConnection上的connectionstatechange
    this.peerConnection.addEventListener('connectionstatechange',事件=>{
    if(this.peerConnection.connectionState==='connected'){
    日志(“连接完成…”);
    }
    });
    }
    这个.startListeningVideoCalls();
    if(data.videoCallOfferChat){
    这是.startReceivingStreams();
    这个.answerVideoCall(data.videoCallOfferChat);
    }
    否则{
    this.offerVideoCall();
    }
    }
    ngOnInit():void{}
    异步startTransmittingStreams(){
    const localStream=wait window.navigator.mediaDevices.getUserMedia({video:true,audio:true});
    localStream.getTracks().forEach(异步跟踪=>{
    日志(“添加跟踪…”,跟踪);
    等待这个.peerConnection.addTrack(track,localStream);
    });
    }
    startReceivingStreams(){
    日志(“开始接收…”);
    让remoteStream=new MediaStream();
    this.peerConnection.ontrack=事件=>{
    console.log(“[addEventListener]远程视频流添加到视频元素…”,事件);
    让remoteVideo:any=document.getElementById('friendUserVideoTrack');
    remoteVideo.srcObject=remoteStream;
    remoteStream.addTrack(event.track);
    }
    }
    私人监听视频通话(){
    if(this.stompService.connected()){
    this.chatSubscription=this.stompService.watch('/text/'+this.currentUser.id).订阅((数据:any)=>{
    让chat=JSON.parse(data.body);
    if(chat.data)
    chat.data=JSON.parse(chat.data);
    if(chat.type==ChatType.VIDEO\u CALL\u ANSWER){
    console.log('Video Call-Answer…',chat);
    if(chat.data.answer){
    //包含RTCConnection应答,然后连接
    console.log('Call accepted',chat.data.answer);
    这个。视频电话应答(聊天);
    }否则{
    //不包含RTCConnection应答:呼叫被收件人拒绝
    log('呼叫被拒绝…');
    }
    }
    if(chat.type==ChatType.ICE_候选者){
    console.log(“与ICE候选人聊天”,聊天);
    this.iceCandidateReceived(chat.data.iceCandidate);
    }
    });
    }
    }
    异步offerVideoCall(){
    var options={offerToReceiveVideo:true,offerToReceiveAudio:true};
    const offer=wait this.peerConnection.createOffer(选项);
    等待这个.peerConnection.setLocalDescription(offer);
    this.sendToSocket(this.createChat(null,ChatType.VIDEO_CALL_OFFER,{'OFFER':OFFER}));
    }
    专用异步应答视频呼叫(receivedChat:Chat){
    如果(收到Chat.data.offer){
    让remoteDescription=新的RTCSessionDescription(receivedChat.data.offer);
    等着吧
    
    import { Component, OnInit, Inject } from '@angular/core';
    import { MAT_DIALOG_DATA } from '@angular/material/dialog';
    import { User } from 'src/app/user/model/user';
    import { RxStompService } from '@stomp/ng2-stompjs';
    import { Subscription } from 'rxjs';
    import { LoginService } from 'src/app/login/service/login.service';
    import { Chat } from 'src/app/chats/model/chat';
    import { ChatType } from 'src/app/chats/model/chat-type';
    import { v4 as uuidv4 } from 'uuid';
    import { CryptoService } from 'src/app/crypto/service/crypto.service';
    
    @Component({
      selector: 'app-video-call',
      templateUrl: './video-call.component.html',
      styleUrls: ['./video-call.component.css']
    })
    export class VideoCallComponent implements OnInit {
    
      currentUser : User;
      friendUser : User;
      chatSubscription : Subscription;
      peerConnection : RTCPeerConnection;
      offer : Chat;
      answer : Chat;
      iceCandidate : Chat;
      generatedIceCandidateCount = 0;
      receivedIceCandidateCount = 0; 
      iceCandidates = new Array<any>(); 
    
      constructor(
        private loginService : LoginService,
        @Inject(MAT_DIALOG_DATA) public data: any,
        private stompService : RxStompService,
        private cryptoService : CryptoService
      ) {
        this.currentUser = this.loginService.getCurrentUser();
        if(data.friendUser){
          this.friendUser = data.friendUser;
          const configuration = {'iceServers': [{'urls': 'stun:stun.l.google.com:19302'}]};
          this.peerConnection = new RTCPeerConnection(configuration);
    
          this.startReceivingStreams();
    
          // Listen for local ICE candidates on the local RTCPeerConnection
          this.peerConnection.addEventListener('icecandidate', event => {
            if (event.candidate) {
              // console.log('ICE Candidate generated', event.candidate);
              console.log("Genrated Candidate ", ++this.generatedIceCandidateCount);
              this.iceCandidates.push(event.candidate);
              // this.sendToSocket(this.createChat(null, ChatType.ICE_CANDIDATE, {'iceCandidate' : event.candidate}));
            }else{
              console.log("Candidates in buffer : ", this.generatedIceCandidateCount); 
              this.iceCandidates.forEach((candidate) => {
                this.sendToSocket(this.createChat(null, ChatType.ICE_CANDIDATE, {'iceCandidate' : candidate}))
              });    
              if(this.iceCandidates.length>0)
                this.startTransmittingStreams();
            }
          });
    
          // Listen for connectionstatechange on the local RTCPeerConnection
          this.peerConnection.addEventListener('connectionstatechange', event => {
            if (this.peerConnection.connectionState === 'connected') {
                console.log("Connection done...");
              }
          });
    
        }
        this.startListeningVideoCalls();
        if (data.videoCallOfferChat){
          this.startReceivingStreams();
          this.answerVideoCall(data.videoCallOfferChat);
        }
        else{
          this.offerVideoCall();
        }
    
      }
      
      ngOnInit(): void {}
    
      async startTransmittingStreams(){
        const localStream = await window.navigator.mediaDevices.getUserMedia({video: true, audio: true});
        localStream.getTracks().forEach(async track => {
            console.log("Adding track...", track);
            await this.peerConnection.addTrack(track, localStream);
        });
      }
    
       startReceivingStreams(){
        console.log("Start receiving...");
        let remoteStream = new MediaStream();
        this.peerConnection.ontrack = event => {
          console.log("[addEventListener] Remote video stream added to the video element...", event);
          let remoteVideo : any = document.getElementById('friendUserVideoTrack');
          remoteVideo.srcObject = remoteStream;
          remoteStream.addTrack(event.track);
        }
      }
    
      private startListeningVideoCalls(){
        if(this.stompService.connected()){
          this.chatSubscription = this.stompService.watch('/text/'+this.currentUser.id).subscribe((data:any)=>{
            let chat = JSON.parse(data.body);
            if(chat.data)
              chat.data = JSON.parse(chat.data);
            if (chat.type == ChatType.VIDEO_CALL_ANSWER) {
              console.log('Video Call Answer ...', chat);
              if (chat.data.answer) {
                // Contains RTCConnection answer then connect
                console.log('Call accepted', chat.data.answer);
                this.videoCallAnswered(chat);
              }else{
                // Doesn't contains RTCConnection answer : call rejected by recipient
                console.log('Call rejected...');
              }
            }
            if(chat.type == ChatType.ICE_CANDIDATE){
              console.log('Chat with ICE Candidate ', chat);
              this.iceCandidateReceived(chat.data.iceCandidate);
            }
          });
        }
      }
    
      async offerVideoCall() {
        var options = { offerToReceiveVideo: true, offerToReceiveAudio: true };
        const offer = await this.peerConnection.createOffer(options);
        await this.peerConnection.setLocalDescription(offer);
        this.sendToSocket(this.createChat(null, ChatType.VIDEO_CALL_OFFER, {'offer' : offer}));
      }
    
      private async answerVideoCall(receivedChat : Chat){
        if (receivedChat.data.offer) {
          let remoteDescription = new RTCSessionDescription(receivedChat.data.offer);
          await this.peerConnection.setRemoteDescription(remoteDescription);
          var options = { offerToReceiveVideo: true, offerToReceiveAudio: true };
          const answer = await this.peerConnection.createAnswer(options);
          await this.peerConnection.setLocalDescription(answer);
          this.sendToSocket(this.createChat(receivedChat.id, ChatType.VIDEO_CALL_ANSWER, {'answer' : answer}));
        }
      }
    
      private async videoCallAnswered(chat : Chat){
        const remoteDesc = new RTCSessionDescription(chat.data.answer);
        await this.peerConnection.setRemoteDescription(remoteDesc);
      }
    
      private createChat(id : string, chatType : ChatType, data : any){
        let chat : Chat = new Chat();
        chat.id = uuidv4();
        chat.textFrom = this.currentUser.id;
        chat.textTo = this.friendUser.id;
        chat.textFromName = this.currentUser.name;
        chat.textToName = this.friendUser.name;
        chat.date = new Date().getTime();
        chat.type = chatType;
        chat.message = this.cryptoService.encrypt(chat.message, this.friendUser.userChat.sk);
        chat.data = JSON.stringify(data);
        return chat;
      }
    
      private sendToSocket(chat : Chat){
        if(this.stompService.connected()){
          this.stompService.publish({
            destination : "/app/text/"+this.friendUser.id,
            body : JSON.stringify(chat)
          });  
        }
      }
    
      private async iceCandidateReceived(iceCandidate : any){
        if(this.peerConnection.remoteDescription){
          try {
            await this.peerConnection.addIceCandidate(new RTCIceCandidate(iceCandidate));
            console.log("Received Count ", ++this.receivedIceCandidateCount); 
          } catch (e) {
              console.error('Error adding received ice candidate', e);
          }
        }
      }
    
    }