まえがき
WebRTC APIのアップデートの概要は、@yusuke84さんの記事「WebRTC Update 2016 Summer」が参考になります。
本題
WebRTCのブラウザ実装としては最後発となるSafariですが、Safari Technology Preview(以下、Safari TP) 34のリリースノートを読むと、
- Added support for receive-only SDP offers through
addTransceiver
と書かれています。意外なことに、ChromeやFirefox、Edgeを出し抜いて、です。
RTCRtpTransceiver
現在のWebRTCのAPI仕様では、ストリームの入出力をより自由に扱えるよう、
- ストリームの入力とコーデックのパラメータ設定等を扱う
RTCRtpSender
- 受信ストリームを扱う
RTCRtpReceiver
が設けられています。Safari TP 34では、これら2つをまとめて送受信を管理するRTCRtpTransceiver
を備えています。
Before RTCRtpTransceiver
現在のChromeやFirefox等では、片方向に音声・映像を送受信する場合は、RTCPeerConnection
にマイクやカメラのMediaStreamTrack
をaddTrack
で追加して、createOffer
やcreateAnswer
でofferToReceiveVideo
やofferToReceiveAnswer
といったオプションを使う必要がありました。例えば、Offerer側がビデオを送信するのみで受信しないようにしたい場合は、次のような感じのコードになります。
const pc = new RTCPeerConnection({iceServers: [/* 中略 */]});
navigator.mediaDevices.getUserMedia({video: true}).then(stream => {
pc.addTrack(stream.getVideoTracks()[0]);
return pc.createOffer({offerToReceiveVideo: false});
}).then(sdp => {
return pc.setLocalDescription(sdp);
}).then(() => {
// ここで、Answerer側にsdpをwebサーバ経由で送信
});
この方法の場合、全オーディオトラック、全ビデオトラックまとめて受信の有無を設定することになります。なお、現在のWebRTCの仕様では、これらのオプションはLegacy Interface Extensionsという扱いになっています。
After RTCRtpTransceiver
RTCRtpTransceiver
を使うと、片方向通信の扱い方が次のように変わります。まず、RTCRtpTransceiver
は次のような手順で作成します。
navigator.mediaDevices.getUserMedia({video: true}).then(stream => {
const pc = new RTCPeerConnection({iceServers: [/* 中略 */]});
const transceiver = pc.addTransceiver(stream.getVideoTracks()[0]);
})
const pc = new RTCPeerConnection({iceServers: [/* 中略 */]});
const transceiver = pc.addTransceiver('video'); // 引数は'video'もしくは'audio'
作成されたRTCRtpTransceiver
には、sender
とreceiver
の2つの属性が設定され、送信(入力)・受信それぞれのMediaStreamTrack
をコントロールできるようになっています。
ここで、次のようにすることで、トラック単位で、送信のみ、受信のみを設定することが可能です。
const transceiver = pc.addTransceiver(stream.getVideoTracks()[0]);
transceiver.receiver.track.enabled = false;
transceiver.setDirection('sendonly');
const transceiver = pc.addTransceiver('video');
transceiver.setDirection('recvonly');
この後で、pc.createOffer()
やpc.createAnswer()
を実行した時に生成されるSDPに、受信する内容が反映されます。次のSDPの例では、確かにa=recvonly
となっているのが確認できます。
v=0
o=- 4056205042783684755 3 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE video
a=msid-semantic: WMS
m=video 9 UDP/TLS/RTP/SAVPF 96 98 99 97 100
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:x4Xi
a=ice-pwd:pqIcVaMdsF/jXsud1MpqZRKz
a=fingerprint:sha-256 B8:0E:77:89:95:23:2B:0D:A9:75:60:8A:CA:A7:21:CA:3B:F9:11:0F:CB:C8:ED:A5:B5:46:B0:71:16:BF:F8:58
a=setup:actpass
a=mid:video
a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:4 urn:3gpp:video-orientation
a=extmap:5 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:6 http://www.webrtc.org/experiments/rtp-hdrext/playout-delay
a=recvonly
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 red/90000
a=rtpmap:98 ulpfec/90000
a=rtpmap:99 H264/90000
a=rtcp-fb:99 ccm fir
a=rtcp-fb:99 nack
a=rtcp-fb:99 nack pli
a=rtcp-fb:99 goog-remb
a=rtcp-fb:99 transport-cc
a=fmtp:99 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:100 rtx/90000
a=fmtp:100 apt=99
ちなみに、sendonly
で全く受信しないRTCPeerConnection
でSDPを生成すると、次のような結果になります。全く受信を行わないので、当然ながら受信に関するIPアドレスやポートの情報が全く追加されていないのが確認できます。
v=0
o=- 3443265369116888093 2 IN IP4 127.0.0.1
s=-
t=0 0
a=msid-semantic: WMS