WebRTC伝送チャネルの確立プロセスの分析

 序文

WebRTCは、リアルタイムのオーディオおよびビデオ通信における幅広いアプリケーションを備えた無料のオープンソースプロジェクトです。シンプルなAPIを介して、ブラウザやモバイルデバイスにリアルタイム通信(RTC)機能を提供します。この目的を最大限に果たすために、WebRTCコンポーネントはまだ最適化されています。公式チームの目標は、共通のプロトコルセットを介して、ブラウザ、モバイル、IoTデバイス間で機能が豊富で高品質の通信を可能にすることです。WebRTCは、リアルタイムのオーディオおよびビデオ通信のプロセスにおいて、特定のマルチメディアデータ伝送チャネルに依存する必要があります。今日は、この伝送チャネルの確立プロセスを見てみましょう。

文章

WebRTCに精通している友人は、PeerConnectionの概念を知っている必要があります。はい、WebRTCはマルチメディアデータの送信を実現するためにPeerConnectionチャネルに依存しています。以下で詳細を見ていきましょう。

1.グローバル初期化

PeerConnectionを正式に作成する前に、ビデオエンコーディングエラー訂正メカニズムFlexFECの有効化、Intel VP8ハードウェアアクセラレーションの有効化、WebRTCの自動ゲイン制御の無効化、ログ印刷の有効化など、いくつかのグローバルモジュールを初期化してパフォーマンススイッチを設定する必要があります。例として、AndroidデバイスとWebRTC76バージョンのモバイル端末の概要を示します。参照コードは次のとおりです。

			PeerConnectionFactory.initialize(
          PeerConnectionFactory.InitializationOptions.builder(appContext)
              .setFieldTrials(fieldTrials)
              .setEnableInternalTracer(true)
              .createInitializationOptions());

グローバルモジュールの初期化が完了したら、PeerConnectionを作成できます。

二、PeerConnectionFactory

注意すると、上記のグローバル初期化プロセスが実行されるときに、クラスのメソッドが使用されることがわかります。同時に、PeerConnectionFactoryは名前でファクトリクラスであり、PeerConnectionFactoryファクトリクラスのインスタンスは、その後のビデオエンコーダおよびデコーダの作成で重要な役割を果たしていることがわかります。

PeerConnectionFactoryファクトリクラスのインスタンスを作成する場合、PeerConnectionチャネル、オーディオ、およびビデオのセットアップ作業の多くが実行されます。それらを個別に紹介しましょう。これは、PeerConnectionFactoryファクトリクラスの機能を理解するのに非常に役立ちます。

1.PeerConnectionチャネル

グローバルPeerConnectionパラメーターは、PeerConnectionに関連する基になるログを出力するかどうかを決定します。参照コードは次のとおりです。

		if (peerConnectionParameters.tracing) {
      PeerConnectionFactory.startInternalTracingCapture(
          Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator
          + "webrtc-trace.txt");
    }

2.オーディオ設定

AACまたはOpusのオーディオエンコーディングをアクティブに設定しない場合、WebRTCはデフォルトでオーディオエンコーディングをISACに設定します。ISACの完全なスペルは、GIPSCompanyによって開発されたInternetSpeech Audio Codecです。これは、無料のオープンソースオーディオコーディング形式であり、VOIPアプリケーションシナリオに非常に適しています。

WebRTCは、元のオーディオデータを保存するためのインターフェイスも提供します。これを使用して、オーディオ収集の問題を特定できます。送信するオーディオにノイズや歪みの問題がある場合は、収集された元のオーディオデータに問題があるかどうかを優先できます。 。元の音声データに問題はないので、エンコード、送信、デコード、再生などのモジュールが原因かどうかを検討します。結局のところ、ネットワークパケット損失は実際の使用で最も一般的な理由の1つです。また、このインターフェイスを使用して、収集されたオーディオデータが正しいかどうかを確認できます。

ただし、設定項目で元の音声データを指定したファイルに保存することはできますが、下層がすでにOpenSL ESを起動している場合は、設定項目は有効になりません。同時に、Androidシステムのハードウェアデバイスのマイクとスピーカーに作用する、オーディオの収集と再生に関連するモジュールもセットアップされます。参照コードは次のとおりです。

		preferIsac = peerConnectionParameters.audioCodec != null
        && peerConnectionParameters.audioCodec.equals(AUDIO_CODEC_ISAC);

    if (peerConnectionParameters.saveInputAudioToFile) {
      if (!peerConnectionParameters.useOpenSLES) {
        Log.d(TAG, "Enable recording of microphone input audio to file");
        saveRecordedAudioToFile = new RecordedAudioToFileController(executor);
      } else {
        Log.e(TAG, "Recording of input audio is not supported for OpenSL ES");
      }
    }

    final AudioDeviceModule adm = createJavaAudioDevice();

3.ビデオ設定

ビデオエンコーディングタイプを設定します。通常、変更されたWebRTCはH264、VP8、およびVP9をサポートします。オーディオエンコーディングフォーマットAACがサポートされていないのと同様に、デフォルトではH264はサポートされていません。また、ソフトコーディングとハードコーディング、ソフトとハードデコーディングも設定されており、一般的にソフトコーディングとソフトデコーディングが対応しており、ハードコーディングとハードデコーディングが対応しています。参照コードは次のとおりです。

		final boolean enableH264HighProfile =
        VIDEO_CODEC_H264_HIGH.equals(peerConnectionParameters.videoCodec);
    final VideoEncoderFactory encoderFactory;
    final VideoDecoderFactory decoderFactory;

    if (peerConnectionParameters.videoCodecHwAcceleration) {
      encoderFactory = new DefaultVideoEncoderFactory(
          rootEglBase.getEglBaseContext(), true /* enableIntelVp8Encoder */, enableH264HighProfile);
      decoderFactory = new DefaultVideoDecoderFactory(rootEglBase.getEglBaseContext());
    } else {
      encoderFactory = new SoftwareVideoEncoderFactory();
      decoderFactory = new SoftwareVideoDecoderFactory();
    }

    factory = PeerConnectionFactory.builder()
                  .setOptions(options)
                  .setAudioDeviceModule(adm)
                  .setVideoEncoderFactory(encoderFactory)
                  .setVideoDecoderFactory(decoderFactory)
                  .createPeerConnectionFactory();
    Log.d(TAG, "Peer connection factory created.");
    adm.release();

3. PeerConnection

PeerConnectionは、WebRTCのマルチメディアデータ伝送チャネルとして理解できます。これは、リアルタイムのオーディオおよびビデオ通信プロセス全体で重要な役割を果たします。同時に、PeerConnectionはWebRTCの3つの外部カプセル化インターフェースの1つです。

オーディオとビデオの開発ドキュメントビデオデータ+マインドマップスキルポイントルート!

PeerConnectionインスタンスの作成は、上記のPeerConnectionFactoryインスタンスに依存します。以下で詳しく見ていきましょう。RTCConfigurationクラスは、ICEサーバー、ICE-TCP、バンドルポリシー、RTCP多重化ポリシー、ECDSA暗号化、DTLS暗号化、SDPセマンティクスなどを含むPeerConnectionに関連する構成パラメータークラスです。

		PeerConnection.RTCConfiguration rtcConfig =
        new PeerConnection.RTCConfiguration(signalingParameters.iceServers);
 
    rtcConfig.tcpCandidatePolicy = PeerConnection.TcpCandidatePolicy.DISABLED;
    rtcConfig.bundlePolicy = PeerConnection.BundlePolicy.MAXBUNDLE;
    rtcConfig.rtcpMuxPolicy = PeerConnection.RtcpMuxPolicy.REQUIRE;
    rtcConfig.continualGatheringPolicy = PeerConnection.ContinualGatheringPolicy.GATHER_CONTINUALLY;
    rtcConfig.keyType = PeerConnection.KeyType.ECDSA;
    rtcConfig.enableDtlsSrtp = !peerConnectionParameters.loopback;
    rtcConfig.sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN;

    peerConnection = factory.createPeerConnection(rtcConfig, pcObserver);

さらに、DataChannelは必要に応じて動的に有効になります。DataChannelチャネルは非常に重要なデータチャネルです。一部のメーカーはこれをシグナリング伝送チャネルとして使用しています。参照コードは次のとおりです。

		if (dataChannelEnabled) {
      DataChannel.Init init = new DataChannel.Init();
      init.ordered = peerConnectionParameters.dataChannelParameters.ordered;
      init.negotiated = peerConnectionParameters.dataChannelParameters.negotiated;
      init.maxRetransmits = peerConnectionParameters.dataChannelParameters.maxRetransmits;
      init.maxRetransmitTimeMs = peerConnectionParameters.dataChannelParameters.maxRetransmitTimeMs;
      init.id = peerConnectionParameters.dataChannelParameters.id;
      init.protocol = peerConnectionParameters.dataChannelParameters.protocol;
      dataChannel = peerConnection.createDataChannel("ApprtcDemo data", init);
    }

第四に、オーディオとビデオのストリームを作成します

1.オーディオストリームを作成します

PeerConnectionが作成されると、オーディオトラックとオーディオソースがすぐに作成されます。オーディオトラックの作成はオーディオソースの作成に依存しますが、PeerConnectionはオーディオトラックに直接作用するため、addTrack()メソッドは次のようになります。対応するオーディオトラックをPeerConnectionオブジェクトにバインドするために呼び出されます。参照コードは次のとおりです。

		audioSource = factory.createAudioSource(audioConstraints);
    localAudioTrack = factory.createAudioTrack(AUDIO_TRACK_ID, audioSource);
    localAudioTrack.setEnabled(enableAudio);

2.ビデオストリームを作成します

PeerConnectionが作成されると、ビデオトラックとビデオソースがすぐに作成されます。ビデオトラックの作成はビデオソースの作成に依存しますが、PeerConnectionはビデオトラックに直接作用するため、addTrack()メソッドは次のようになります。対応するビデオトラックをPeerConnectionオブジェクトにバインドするために呼び出されます。

ただし、ビデオはローカルプレビューのニーズを満たす必要があり、VideoCapturerオブジェクトインスタンスの初期化はビデオソースの監視イベントをバインドしてから収集を開始する必要があるため、ビデオトラックとビデオソースの作成はオーディオとは異なります。 Androidデバイスのカメラのローカル画像データ。同時に、作成されたビデオトラックは、addSink()メソッドを呼び出すことによってビデオのVideoSinkオブジェクトインスタンスもバインドします。オブジェクトインスタンスは、PeerConnectionオブジェクトインスタンスを作成するときにパラメーターを渡すことによって設定されます。参照コードは次のとおりです。

		surfaceTextureHelper =
        SurfaceTextureHelper.create("CaptureThread", rootEglBase.getEglBaseContext());
    videoSource = factory.createVideoSource(capturer.isScreencast());
    capturer.initialize(surfaceTextureHelper, appContext, videoSource.getCapturerObserver());
    capturer.startCapture(videoWidth, videoHeight, videoFps);

    localVideoTrack = factory.createVideoTrack(VIDEO_TRACK_ID, videoSource);
    localVideoTrack.setEnabled(renderVideo);
    localVideoTrack.addSink(localRender);

 したがって、ローカルカメラのビデオ画像データのフローは非常に明確です。最初にVideoCapturerオブジェクトインスタンスによって収集され、次にビデオソースに流れ、次にビデオトラックに流れ、最後にPeerConnectionオブジェクトインスタンスに流れて、マルチメディアデータの送信。

5.SDPネゴシエーション

ローカルオーディオデータとビデオデータが用意されているので、残りの作業内容は、どのマルチメディアデータを送信するか、およびマルチメディアデータをどのように送信するかをリモートエンドとネゴシエートすることです。これには当然、WebRTCの従来のSDPネゴシエーションメカニズムが含まれます。SDP(セッション記述プロトコル)はセッション記述プロトコルです。WebRTCはSDPを介してネゴシエートし、ローカルおよびリモートでSDP情報を交換およびネゴシエートして、呼び出し要件を満たすセッションを作成します。伝送チャネルのデータコンテンツを決定します。SDPネゴシエーションは、オーディオおよびビデオ通信のWebRTCの基盤であり、オーディオおよびビデオの対話プロセス全体で重要な役割を果たします。

1.オファーを作成します

オファーは、WebRTCのローカルマルチメディア機能を記述するために使用されるSDP情報のコレクションです。オファー作成の実際のロジックはネイティブレイヤーにあり、Javaレイヤーは外部インターフェイスcreateOffer()メソッドのみを提供します。Androidシステム開発に精通している友人は、JNIをよく理解している必要があります。Javaロジックレイヤーとネイティブボトムレイヤーの間のブリッジレイヤーとして、JNIモジュールはJavaプログラミング言語と他のプログラミング言語の混合開発を簡単に実現できます。参照コードは次のとおりです。

  public void createOffer(SdpObserver observer, MediaConstraints constraints) {
    nativeCreateOffer(observer, constraints);
  }

オファーのSDP情報には、ローカルマルチメディア機能が含まれます。メディア記述情報の表現形式は次のとおりです。

m=<メディアタイプ><ポート><プロトコル><フォーマットタイプ>

セッションの説明には、オーディオ、ビデオ、テキストなど、複数のメディアの説明が含まれる場合があります。各メディアの説明は「m=」フィールドで始まり、次の「m =」で終わります。もちろん、SDPセッションの説明全体で終わる場合もあります。

その中で、<メディアタイプ>は、ビデオ、オーディオ、テキスト、アプリケーション、およびメッセージのいくつかのタイプを定義し、それらが将来追加されることを排除するものではありません。メディアストリームを送信するためのポートである<port>。このフィールドの意味は、「c=」フィールドと<protocol>フィールドによって異なります。

階層的にエンコードされたコードストリームの場合、送信にユニキャストアドレスを使用する場合は、これらのコードストリームを区別するためにポートを使用する必要があります。具体的な形式は次のとおりです。

m=<メディアタイプ><ポート>くポート番号><プロトコル><フォーマットタイプ>

この場合、ポートの意味はトランスポートプロトコルによって異なります。RTPプロトコルの場合、デフォルトでは、偶数のポートのみがRTPデータの送信に使用され、対応するポートは1ずつ増加してRTCPデータを送信します。「c=」フィールドで複数のアドレスが使用され、同様に「m =」フィールドで複数のポートが使用されている場合、これらのアドレスとポートは1対1で対応していると見なされます。

<protocol>は送信プロトコルを指し、送信プロトコルは「c=」フィールドに関連しています。たとえば、「c =」フィールドのIP4フィールドは、IP4を介したプロトコルを示します。

 教材コレクションのアドレス:https://docs.qq.com/doc/DQm1VTHBlQmdmTlN2

<protocol>フィールドが「RTP/AVP」または「RTP/SAVP」の場合、メディア形式はRTPペイロード形式の番号を示します。リンクリストが表示される場合は、リンクリスト内のすべてのメディア形式を現在のメディアトラックに使用できることを意味しますが、最初のメディア形式がデフォルトの形式です。「a=remap:」属性は、メディアフォーマット番号とメディアフォーマットを動的に一致させるために使用されます。「a=fmtp:」属性は、メディア形式の特定のパラメーターを記述するために使用できます。

<protocol>フィールドがUDPの場合、メディア形式はメディアタイプをオーディオ、ビデオ、テキスト、アプリケーション、またはメッセージとして指定します。これらのメディアタイプは、対応するUDP送信パケット形式も定義します。

     媒体名称
     m=  (media name and transport address)

     媒体标题
     i=* (media title)

     连接信息
     c=* (connection information -- optional if included at session level)

     带宽信息行
     b=* (zero or more bandwidth information lines)

     密钥
     k=* (encryption key)

     媒体属性行
     a=* (zero or more media attribute lines)

完全なSDPの例を通して、SDPがどのように見えるかを見てみましょう。

v = 0

o =-7644049451648220451 2 IN IP4 127.0.0.1

s =-

t = 0 0

a = group:BUNDLEオーディオビデオ

a = msid-セマンティック:WMS ARDAMS

m = audio 44585 UDP / TLS / RTP / SAVPF 111103104 9102 0 8106105 13110112113126

c = IN IP4 172.31.200.23

a = rtcp:9 IN IP4 0.0.0.0

a = candidate:2586587190 1 udp 2122260223 172.31.200.2344585typホスト生成0ネットワークID3ネットワークコスト10

a = candidate:559267639 1 udp 2122202367 :: 145075typホスト生成0ネットワークID2

a = candidate:1510613869 1 udp 2122129151 127.0.0.134137typホスト生成0ネットワークID1

a = ice-ufrag:Rcuq

a = ice-pwd:OxDSE1pHNWhgcdHaX / 3cYLE1

a = ice-options:trickle renomination

a = fingerprint:sha-256 49:B6:A0:48:F8:EB:82:1D:FB:DE:B9:22:33:0E:91:EE:60:34:73:45:2B:C3 :92:3A:0B:0D:FF:B1:EF:AE:8E:29

a = setup:actpass

a = mid:audio

a = extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level

a = sendrecv

a = rtcp-mux

a = rtpmap:111 work / 48000/2

a = rtcp-fb:111transport-cc

a = fmtp:111 minptime = 10; useinbandfec = 1

a = rtpmap:103 ISAC / 16000

a = rtpmap:104 ISAC / 32000

a = rt "

2.回答を設定します

AnswerのSDP情報は、実際にはリモートクライアントによって送信された反対側のSDP記述情報であり、ローカルのオファーSDP記述情報に対応し、一方はローカルで、もう一方はリモートです。ただし、リモートSDP情報をローカルエンドに設定する必要があります。これは、SDPネゴシエーションプロセスに不可欠な部分です。AnswerのSDP情報の特定のフィールドの意味は上記で紹介されているので、ここでは繰り返しません。参照コードは次のとおりです。

				peerConnectionClient.setRemoteDescription(sdp);
        if (!signalingParameters.initiator) {
          logAndToast("Creating ANSWER...");
          peerConnectionClient.createAnswer();
        }

リモートSDP記述の設定は、onRemoteDescription()コールバックイベントをリッスンすることによって行われることに注意してください。上記のコードを見ると、回答の説明情報を作成するためのロジックもいくつかあることがわかります。実際、これはオファーとアンサーの関係が相対的であるためです。ローカルがPeerConnectionチャネルの確立のイニシエーターである場合、最初にオファーを作成する必要がありますが、このオファーは反対の観点からはリモートアンサーです。終わり。オファーとアンサーの交換プロセスについては、次の図を参照してください。

6.伝送チャネルの確立

WebRTC伝送チャネルの確立は、候補の設定にも依存します。PeerConnectionチャネル確立のイニシエーターがローカルSDP情報を作成および設定した後、ICE候補の収集を開始し、収集された結果はに通知されます。 onIceCandidateコールバックイベントを介して上位層に移動し、sendLocalIceCandidate()メソッドを呼び出してピアに送信します。ピアは候補を受信した後、addRemoteIceCandidate()メソッドを呼び出して、候補を対応するPeerConnectionオブジェクトにバインドします。同様に、ローカルエンドもリモートエンドの候補をバインドし、ローカルエンドとリモートエンドは対応する候補のセットを介して最終的な通信を完了します。しかし、このプロセスでは、さまざまな理由により、SDPの再交渉プロセスにも直面する可能性があります。

結論は

リアルタイムのオーディオおよびビデオ通信のプロセスでは、WebRTCは特定のマルチメディアデータ伝送チャネルに依存する必要があります。この記事では、この伝送チャネルの確立プロセスについて基本的に説明しました。ただし、この記事では非常に単純なチャネル確立モデルのみを紹介します。実際、チャネル全体の確立と使用中には他にも多くの問題が発生します。スペースの制限により、この記事は拡張されません。関心のあるパートナーは、コメントメッセージを歓迎します。

おすすめ

転載: blog.csdn.net/m0_60259116/article/details/123928135