webRTC信令机制

webRTC官网关于信令的解释
Imagine Alice is trying to call Eve. Here’s the full offer/answer mechanism in all its gory detail:

Alice creates an RTCPeerConnection object.
Alice creates an offer (an SDP session description) with the RTCPeerConnection createOffer() method.
Alice calls setLocalDescription() with his offer.
Alice stringifies the offer and uses a signaling mechanism to send it to Eve.

Eve calls setRemoteDescription() with Alice’s offer, so that her RTCPeerConnection knows about Alice’s setup.
Eve calls createAnswer(), and the success callback for this is passed a local session description: Eve’s answer.
Eve sets her answer as the local description by calling setLocalDescription().
Eve then uses the signaling mechanism to send her stringified answer back to Alice.
Alice sets Eve’s answer as the remote session description using setRemoteDescription().

想象爱丽丝试图打电话给伊芙。这里是所有的详细的全部提供/回答机制:

Alice创建一个RTCPeerConnection对象。
Alice 使用RTCPeerConnection createOffer()方法创建一个offer(一个SDP会话描述)。
Alice 用他的提议调用setLocalDescription()。
Alice对提议进行字符串化,并使用信令机制将其发送给Eve。

Eve 使用Alice的提供调用setRemoteDescription(),以便她的RTCPeerConnection知道Alice的设置。
Eve调用createAnswer(),并且为此的成功回调传递了本地会话描述:Eve的答案。
Eve通过调用setLocalDescription()将她的答案设置为本地描述。
Eve然后使用信令机制将她的字符串答案发回给Alice。
Alice使用setRemoteDescription()将Eve的答案设置为远程会话描述。

    /**
     *
     * 创建一个SDP约束,并将sdp传入createOffer之中 
     */
    // Create SDP constraints.
    sdpMediaConstraints = new MediaConstraints();
    sdpMediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair(
        "OfferToReceiveAudio", "true"));
    if (videoCallEnabled || peerConnectionParameters.loopback) {
      sdpMediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair(
          "OfferToReceiveVideo", "true"));
    } else {
      sdpMediaConstraints.mandatory.add(new MediaConstraints.KeyValuePair(
          "OfferToReceiveVideo", "false"));
    }
 /**
   * 创建一个offer
   */
  public void createOffer() {
    executor.execute(new Runnable() {
      @Override
      public void run() {
        if (peerConnection != null && !isError) {
          Log.d(TAG, "PC Create OFFER");
          isInitiator = true;
          peerConnection.createOffer(sdpObserver, sdpMediaConstraints);
        }
      }
    });
  }
  /**
     * offer信令创建成功后会调用SdpObserver
     * 监听中的onCreateSuccess()响应函数
     * 在这里接受端会通过peerConnection.setLocalDescription
     * 将offer信令(SDP描述符)赋给自己的peerConnection对象,
     * 同时将offer信令发送给发送方 。
     */
  private class SDPObserver implements SdpObserver {

    @Override
    public void onCreateSuccess(final SessionDescription origSdp) {
      if (localSdp != null) {
        reportError("Multiple SDP create.");
        return;
      }
      String sdpDescription = origSdp.description;
      if (preferIsac) {
        sdpDescription = preferCodec(sdpDescription, AUDIO_CODEC_ISAC, true);
      }
      if (videoCallEnabled && preferH264) {
        sdpDescription = preferCodec(sdpDescription, VIDEO_CODEC_H264, false);
      }
      final SessionDescription sdp = new SessionDescription(
          origSdp.type, sdpDescription);
      localSdp = sdp;
      executor.execute(new Runnable() {
        @Override
        public void run() {
          if (peerConnection != null && !isError) {
            Log.d(TAG, "Set local SDP from " + sdp.type);
            /**
             * 发送方在onCreateSuccess()监听响应函数中调用
             * peerConnection.setLocalDescription将
             * answer信令(SDP描述符)
             * 赋给自己的PC对象,同时将answer信令发送给B 。
             */
            peerConnection.setLocalDescription(sdpObserver, sdp);
          }
        }
      });
    }

    @Override
    public void onSetSuccess() {
      executor.execute(new Runnable() {
        @Override
        public void run() {
          if (peerConnection == null || isError) {
            return;
          }
          if (isInitiator) {
            // For offering peer connection we first create offer and set
            // local SDP, then after receiving answer set remote SDP.
            if (peerConnection.getRemoteDescription() == null) {
              // We've just set our local SDP so time to send it.
              Log.d(TAG, "Local SDP set succesfully");
              events.onLocalDescription(localSdp);
            } else {
              // We've just set remote description, so drain remote
              // and send local ICE candidates.
              Log.d(TAG, "Remote SDP set succesfully");
              drainCandidates();
            }
          } else {
            // For answering peer connection we set remote SDP and then
            // create answer and set local SDP.
            if (peerConnection.getLocalDescription() != null) {
              // We've just set our local SDP so time to send it, drain
              // remote and send local ICE candidates.
              Log.d(TAG, "Local SDP set succesfully");
              events.onLocalDescription(localSdp);
              drainCandidates();
            } else {
              // We've just set remote SDP - do nothing for now -
              // answer will be created soon.
              Log.d(TAG, "Remote SDP set succesfully");
            }
          }
        }
      });
    }

    @Override
    public void onCreateFailure(final String error) {
      reportError("createSDP error: " + error);
    }

    @Override
    public void onSetFailure(final String error) {
      reportError("setSDP error: " + error);
    }
  }
/**
 * 发送方收到接收方的offer信令后,利用 
 * peerConnection.setRemoteDescription()
 * 方法将接收方的SDP描述赋给发送方的peerConnection对象。
 */
 public void setRemoteDescription(final SessionDescription sdp) {
    executor.execute(new Runnable() {
      @Override
      public void run() {
        if (peerConnection == null || isError) {
          return;
        }
        String sdpDescription = sdp.description;
        if (preferIsac) {
          sdpDescription = preferCodec(sdpDescription, AUDIO_CODEC_ISAC, true);
        }
        if (videoCallEnabled && preferH264) {
          sdpDescription = preferCodec(sdpDescription, VIDEO_CODEC_H264, false);
        }
        if (videoCallEnabled && peerConnectionParameters.videoStartBitrate > 0) {
          sdpDescription = setStartBitrate(VIDEO_CODEC_VP8, true,
              sdpDescription, peerConnectionParameters.videoStartBitrate);
          sdpDescription = setStartBitrate(VIDEO_CODEC_VP9, true,
              sdpDescription, peerConnectionParameters.videoStartBitrate);
          sdpDescription = setStartBitrate(VIDEO_CODEC_H264, true,
              sdpDescription, peerConnectionParameters.videoStartBitrate);
        }
        if (peerConnectionParameters.audioStartBitrate > 0) {
          sdpDescription = setStartBitrate(AUDIO_CODEC_OPUS, false,
              sdpDescription, peerConnectionParameters.audioStartBitrate);
        }
        Log.d(TAG, "Set remote SDP.");
        SessionDescription sdpRemote = new SessionDescription(
            sdp.type, sdpDescription);
        peerConnection.setRemoteDescription(sdpObserver, sdpRemote);
      }
    });
  }

接收方收到发送方的answer信令后,利用peerConnection.setRemoteDescription()方法将发送方的SDP描述赋给接收方的peerConnection对象。

这样接收方和发送方的信令交换已经完成了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章