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對象。

這樣接收方和發送方的信令交換已經完成了

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