WebRTC はブラウザ上で音声とビデオの通信を実装します

概要

WebRTC  (Web Real-Time Communications) は、ネットワーク アプリケーションまたはサイトが仲介者なしでブラウザ間でピアツーピア (ピアツーピア) 接続を確立し、ビデオ ストリーミングや送信を実現できるリアルタイム通信テクノロジです。オーディオ ストリームまたはその他の任意のデータ。WebRTC に含まれるこれらの標準により、ユーザーはプラグインやサードパーティ ソフトウェアをインストールしなくても、ピアツーピア (Peer-to-Peer) データ共有や電話会議を作成できるようになります。

webRTC プロトコルの概要

インタラクティブ接続確立 (ICE) は、 Web ブラウザがピアに接続できるようにするフレームワークです。ピア A からピア B への直接接続が機能しない理由は数多くあります。オープン接続を妨げるファイアウォールをバイパスし、ほとんどの場合と同様にデバイスにパブリック IP アドレスがない場合は一意のアドレスを与え、ルーターがピアとの直接通信を許可していない場合はサーバーを介してデータを中継する必要があります。接続する。ICE は、以下で説明するように、この目的のために STUN サーバーや TURN サーバーを使用します。

気絶

Session Transverse Utility for NAT (STUN) は、パブリック アドレスを検出し、ピアへの直接接続を妨げるルータ内の制限を特定するプロトコルです。

クライアントは、インターネット上の STUN サーバーにリクエストを送信します。STUN サーバーは、クライアントのパブリック アドレスと、クライアントがルーター NAT の背後でアクセス可能かどうかを応答します。
 

NAT

ネットワーク アドレス変換 (NAT) は、デバイスにパブリック IP アドレスを与えるために使用されます。ルーターにはパブリック IP アドレスがあり、ルーターに接続されている各デバイスにはプライベート IP アドレスがあります。リクエストは、一意のポートを使用して、デバイスのプライベート IP からルーターのパブリック IP に変換されます。こうすることで、各デバイスに一意のパブリック IP を持たせる必要がなくなりますが、それでもインターネット上で検出可能になります。

一部のルーターでは、ネットワーク上のデバイスに接続できるユーザーが制限されます。これは、たとえ STUN サーバーによってパブリック IP アドレスが見つかったとしても、誰も接続を作成できないことを意味する可能性があります。この場合、ステアリングを切る必要があります。

振り向く

NAT を使用する一部のルーターでは、「対称 NAT」と呼ばれる制限が採用されています。これは、ルーターが以前に接続したことのあるピアからの接続のみを受け入れることを意味します。

NAT 周りのリレーを使用したトランスバース (転送) は、 TURN サーバーへの接続を開き、そのサーバーを介してすべての情報をリレーすることにより、対称 NAT 制限をバイパスするように設計されています。TURN サーバーへの接続を作成し、すべての取引相手にパケットをサーバーに送信するように指示し、パケットはサーバーに転送されます。これには明らかにオーバーヘッドがかかるため、他にオプションがない場合にのみ使用されます。
 

SDP

セッション記述プロトコル (SDP) は、データ転送時に 2 つのピアが相互に理解できるように、解像度、形式、コーデック、暗号化など、接続のマルチメディア コンテンツを記述するための標準です。これは本質的に、メディア コンテンツそのものではなく、コンテンツを説明するメタデータです。

したがって、技術的に言えば、SDP は実際にはプロトコルではなく、デバイス間の共有メディア接続を記述するために使用されるデータ形式です。

SDP の文書化はこのドキュメントの範囲をはるかに超えていますが、ここで注目に値することがいくつかあります。

webRTC API

WebRTCでは主にブラウザに3つの機能を持たせることができます。

  • 音声とビデオを取得する
  • 音声およびビデオ通信を行う
  • 任意のデータを通信する

WebRTC は上記 3 つの機能に対応して 3 つの API に分かれています。

  • MediaStream (別名 getUserMedia)
  • RTCPeerConnection
  • RTCデータチャネル

ユーザーメディアの取得

概要

navigator.getUserMedia メソッドは現在、ブラウザでオーディオ (マイク経由) とビデオ (カメラ経由) を取得するために主に使用されており、将来的にはディスクやセンサーなどの任意のデータ ストリームを取得するために使用できるようになります。

次のコードは、ブラウザが getUserMedia メソッドをサポートしているかどうかを確認するために使用されます。

navigator.getUserMedia  = navigator.getUserMedia ||
                          navigator.webkitGetUserMedia ||
                          navigator.mozGetUserMedia ||
                          navigator.msGetUserMedia;

if (navigator.getUserMedia) {
    // 支持
} else {
    // 不支持
}

Chrome 21、Opera 18、Firefox 17 はこの方法をサポートしています。現時点では、IE はまだサポートしていません。上記のコード内の msGetUserMedia は、将来の互換性を確保するためのものです。

getUserMedia メソッドは 3 つのパラメータを受け入れます。

navigator.getUserMedia({
    video: true, 
    audio: true
}, onSuccess, onError);

getUserMedia の最初のパラメータは、どのマルチメディア デバイスを取得するかを示すオブジェクトです。上記のコードは、カメラとマイクの取得を示します。onSuccess は、マルチメディア デバイスが正常に取得されたときに呼び出されるコールバック関数です。onError もコールバック関数です。マルチメディア デバイスの取得時 失敗時に呼び出されます。

以下に例を示します。

var constraints = {video: true};

function onSuccess(stream) {
  var video = document.querySelector("video");
  video.src = window.URL.createObjectURL(stream);
}

function onError(error) {
  console.log("navigator.getUserMedia error: ", error);
}

navigator.getUserMedia(constraints, onSuccess, onError);

Web ページで getUserMedia メソッドが使用されている場合、ブラウザはマイクまたはカメラの呼び出しを許可するかどうかをユーザーに尋ねます。ユーザーが同意した場合はコールバック関数 onSuccess が呼び出され、ユーザーが拒否した場合はコールバック関数 onError が呼び出されます。

onSuccess コールバック関数のパラメータはデータ ストリーム オブジェクト ストリームです。stream.getAudioTracks メソッドと stream.getVideoTracks メソッドはそれぞれ、データ ストリームに含まれるオーディオ トラックとビデオ トラックをメンバーとする配列を返します。使用される音源とカメラの数によって、オーディオ トラックとビデオ トラックの数が決まります。たとえば、1 台のカメラのみを使用してビデオをキャプチャし、オーディオをキャプチャしない場合、ビデオ トラックの数は 1、オーディオ トラックの数は 0 になります。各オーディオ トラックとビデオ トラックには、種類 (ビデオまたはオーディオ) を示す kind 属性と、ラベル属性 (FaceTime HD カメラ (内蔵) など) があります。

onError コールバック関数は、Error オブジェクトをパラメータとして受け入れます。Error オブジェクトの code 属性には、エラーの種類を示す次の値があります。

  • PERMISSION_DENIED : ユーザーは情報の提供を拒否しました。
  • NOT_SUPPORTED_ERROR : ブラウザはハードウェア デバイスをサポートしていません。
  • MANDATORY_UNSATISFIED_ERROR : 指定されたハードウェア デバイスを検出できませんでした。

例: カメラを取得する

次に、getUserMedia メソッドを使用して、カメラでキャプチャした画像を Web ページに表示します。

まず、Web ページにビデオ要素を配置する必要があります。画像はこの要素内に表示されます。

<video id="webcam"></video>

次に、コードを使用してこの要素を取得します。

function onSuccess(stream) {
    var video = document.getElementById('webcam');
}

そして、この要素の src 属性をデータストリームにバインドすると、カメラで捉えた画像を表示することができます。

function onSuccess(stream) {
    var video = document.getElementById('webcam');
    if (window.URL) {
	    video.src = window.URL.createObjectURL(stream);
	} else {
		video.src = stream;
	}

	video.autoplay = true; 
	// 或者 video.play();
}

if (navigator.getUserMedia) {
	navigator.getUserMedia({video:true}, onSuccess);
} else {
	document.getElementById('webcam').src = 'somevideo.mp4';
}

Chrome と Opera では、URL.createObjectURL メソッドはメディア データ ストリーム (MediaStream) をバイナリ オブジェクト URL (Blob URL) に変換し、video 要素の src 属性の値として使用できます。Firefox では、メディア データ ストリームを src 属性の値として直接使用できます。Chrome と Opera では、getUserMedia で取得した音声データを audio 要素または video 要素の値として直接使用することもできます。つまり、音声も取得した場合、上記のコードで再生されるビデオには音声が付きます。

カメラを入手する主な用途の 1 つは、ユーザーがカメラで自分の写真を撮影できるようにすることです。Canvas API には、ビデオのフレームを Canvas 要素に変換できる ctx.drawImage(video, 0, 0) メソッドがあります。これにより、スクリーンショットの撮影が非常に簡単になります。

<video autoplay></video>
<img src="">
<canvas style="display:none;"></canvas>

<script>
  var video = document.querySelector('video');
  var canvas = document.querySelector('canvas');
  var ctx = canvas.getContext('2d');
  var localMediaStream = null;

  function snapshot() {
    if (localMediaStream) {
      ctx.drawImage(video, 0, 0);
      // “image/webp”对Chrome有效,
      // 其他浏览器自动降为image/png
      document.querySelector('img').src = canvas.toDataURL('image/webp');
    }
  }

  video.addEventListener('click', snapshot, false);

  navigator.getUserMedia({video: true}, function(stream) {
    video.src = window.URL.createObjectURL(stream);
    localMediaStream = stream;
  }, errorCallback);
</script>

例: マイク音声のキャプチャ

ブラウザ経由で音声を取り込むにはWeb Audio APIが必要です。

window.AudioContext = window.AudioContext ||
                      window.webkitAudioContext;

var context = new AudioContext();

function onSuccess(stream) {
	var audioInput = context.createMediaStreamSource(stream);
	audioInput.connect(context.destination);
}

navigator.getUserMedia({audio:true}, onSuccess);

キャプチャ資格

getUserMedia メソッドの最初のパラメーターでは、キャプチャ オブジェクトの指定に加えて、高解像度 (または VGA 標準) ビデオの記録の制限など、いくつかの制限も指定できます。

var hdConstraints = {
  video: {
    mandatory: {
      minWidth: 1280,
      minHeight: 720
    }
  }
};

navigator.getUserMedia(hdConstraints, onSuccess, onError);

var vgaConstraints = {
  video: {
    mandatory: {
      maxWidth: 640,
      maxHeight: 360
    }
  }
};

navigator.getUserMedia(vgaConstraints, onSuccess, onError);

MediaStreamTrack.getSources()

マシンに複数のカメラ/マイクがある場合は、MediaStreamTrack.getSources メソッドを使用して、使用するカメラ/マイクを指定する必要があります。

MediaStreamTrack.getSources(function(sourceInfos) {
  var audioSource = null;
  var videoSource = null;

  for (var i = 0; i != sourceInfos.length; ++i) {
    var sourceInfo = sourceInfos[i];
    if (sourceInfo.kind === 'audio') {
      console.log(sourceInfo.id, sourceInfo.label || 'microphone');

      audioSource = sourceInfo.id;
    } else if (sourceInfo.kind === 'video') {
      console.log(sourceInfo.id, sourceInfo.label || 'camera');

      videoSource = sourceInfo.id;
    } else {
      console.log('Some other kind of source: ', sourceInfo);
    }
  }

  sourceSelected(audioSource, videoSource);
});

function sourceSelected(audioSource, videoSource) {
  var constraints = {
    audio: {
      optional: [{sourceId: audioSource}]
    },
    video: {
      optional: [{sourceId: videoSource}]
    }
  };

  navigator.getUserMedia(constraints, onSuccess, onError);
}

上記のコードは、MediaStreamTrack.getSources メソッドのコールバック関数がローカル カメラとマイクのリストを取得し、最後に使用するカメラとマイクを指定できることを示しています。

RTCPeerConnection、RTCDataChannel

RTCPeerConnectionl

RTCPeerConnection の役割は、ブラウザ間でデータの「ピアツーピア」通信を確立すること、つまり、ブラウザによって取得されたマイクまたはカメラのデータを別のブラウザに送信することです。これには、信号処理、マルチメディア エンコード/デコード、ポイントツーポイント通信、データ セキュリティ、帯域幅管理など、多くの複雑な作業が含まれます。

異なるクライアント間のオーディオ/ビデオ伝送はサーバーを経由する必要はありません。ただし、2 つのクライアント間の接続はサーバーを経由する必要があります。サーバーは主に 2 種類のデータを転送します。

  • 通信内容のメタデータ:セッションを開始/終了するコマンド、メディアファイルのメタデータ(エンコード形式、メディアタイプ、帯域幅)など
  • ネットワーク通信のメタデータ: IP アドレス、NAT ネットワーク アドレス変換、ファイアウォールなど。

WebRTCプロトコルはサーバーとの通信方式を規定していないため、WebSocketなどさまざまな方式が利用可能です。サーバーを介して、2 つのクライアントはセッション記述プロトコル (SDP プロトコル) に従って双方のメタデータを交換します。

以下に例を示します。

var signalingChannel = createSignalingChannel();
var pc;
var configuration = ...;

// run start(true) to initiate a call
function start(isCaller) {
    pc = new RTCPeerConnection(configuration);

    // send any ice candidates to the other peer
    pc.onicecandidate = function (evt) {
        signalingChannel.send(JSON.stringify({ "candidate": evt.candidate }));
    };

    // once remote stream arrives, show it in the remote video element
    pc.onaddstream = function (evt) {
        remoteView.src = URL.createObjectURL(evt.stream);
    };

    // get the local stream, show it in the local video element and send it
    navigator.getUserMedia({ "audio": true, "video": true }, function (stream) {
        selfView.src = URL.createObjectURL(stream);
        pc.addStream(stream);

        if (isCaller)
            pc.createOffer(gotDescription);
        else
            pc.createAnswer(pc.remoteDescription, gotDescription);

        function gotDescription(desc) {
            pc.setLocalDescription(desc);
            signalingChannel.send(JSON.stringify({ "sdp": desc }));
        }
    });
}

signalingChannel.onmessage = function (evt) {
    if (!pc)
        start(false);

    var signal = JSON.parse(evt.data);
    if (signal.sdp)
        pc.setRemoteDescription(new RTCSessionDescription(signal.sdp));
    else
        pc.addIceCandidate(new RTCIceCandidate(signal.candidate));
};

RTCPeerConnection にはブラウザ プレフィックスがあり、Chrome ブラウザおよび Firefox ブラウザでは webkitRTCPeerConnection になります。

mozRTCPeerConnection。Google は、ブラウザ間の違いを抽象化するために関数ライブラリadapter.jsを保守しています。

RTCデータチャネル

RTCDataChannel の機能は、ピア間で任意のデータを送信することです。API は WebSocket と同じです。

以下に例を示します。

 

var pc = new webkitRTCPeerConnection(servers,
  {optional: [{RtpDataChannels: true}]});

pc.ondatachannel = function(event) {
  receiveChannel = event.channel;
  receiveChannel.onmessage = function(event){
    document.querySelector("div#receive").innerHTML = event.data;
  };
};

sendChannel = pc.createDataChannel("sendDataChannel", {reliable: false});

document.querySelector("button#send").onclick = function (){
  var data = document.querySelector("textarea#send").value;
  sendChannel.send(data);
};

Chrome 25、Opera 18、Firefox 22 は RTCDataChannel をサポートします。

外部関数ライブラリ

これら 2 つの API は複雑であるため、操作には通常、外部関数ライブラリが使用されます。現在、ビデオ チャット用の関数ライブラリにはSimpleWebRTCeasyRTC、およびwebRTC.ioが含まれ、ピアツーピア通信用の関数ライブラリにはPeerJSおよびSharefestが含まれます。

以下は SimpleWebRTC の例です。
 

var webrtc = new WebRTC({
  localVideoEl: 'localVideo',
  remoteVideosEl: 'remoteVideos',
  autoRequestMedia: true
});

webrtc.on('readyToCall', function () {
    webrtc.joinRoom('My room name');
});

以下は PeerJS の例です。

var peer = new Peer('someid', {key: 'apikey'});
peer.on('connection', function(conn) {
  conn.on('data', function(data){
    // Will print 'hi!'
    console.log(data);
  });
});

// Connecting peer
var peer = new Peer('anotherid', {key: 'apikey'});
var conn = peer.connect('someid');
conn.on('open', function(){
  conn.send('hi!');
});

オリジナルの WebRTC はブラウザ上で音声とビデオの通信を実装します - Nuggets

★記事末尾の名刺では、オーディオ・ビデオ開発学習教材(FFmpeg、webRTC、rtmp、hls、rtsp、ffplay、srs)やオーディオ・ビデオ学習ロードマップ等を無料で受け取ることができます。

以下を参照してください!

 

おすすめ

転載: blog.csdn.net/yinshipin007/article/details/132212115