Download - WebRTC multitrack / multistream
WebRTC multi-track / multi-stream挙動から見たブラウザの現状
2015.09.29インフォコムがねこまさし(我如古正志)@massie_g
いきなり余談
懺悔 (1) setRemoteDescription() 問題• peer.setRemoteDescript() は非同期実行
– 直後に createAnswer() するとエラーになることがある– Chrome では経験したことはないが、 Firefox では時々発生
// NGpeer.setRemoteDescription(offer);peer.createAnswer( ... );
//OKpeer.setRemoteDescription(offer, function (evt) { peer.createAnswer( ... ); }, function (err) { … });
※ 私の HTML5Experts.jp の記事はコールバックになってません ※ こっちは修正済です• https://lab.infocom.co.jp/demo/webrtc-hand-signaling-easy.html
懺悔 (2) onnegotiationneeded() 問題• 前回「 onnegotiationneeded() は無視してます」と言ったら怒られた• その後、発火タイミングが Firefox も Chrome と同じになった
– 接続確立前も peer.addStream(localStream) で発火• createDataChannel() でも??
• ケース 1 : 接続確立前– peer.localDescription の有無で判断– 確立前 (localDescription 無し)なら、何もしない
• 自分が Offer 側になるか、 Answer 側になるか決まっていないので• ケース 2: 接続確立後
– Offer 側か、 Answer 側かを判断• peer.localDescription.type
– Offer 側なら• peer.createOffer() send Offer
– Answer 側なら• request Offer• Offer 側で peer.createOffer() send Offer• Answer 側で peer.createAnswer() → send Answer
懺悔 (3) revokeObjectURL() 未使用• URL 取得– video.src = window.URL.createObjectURL(stream);
• URL 解放– window.URL.rekoveObjectURL(video.src);※ おそらく、 Single Page Application なら明示的に開放した方が良い
本題• multi-track について• Firefox の multi-stream について• Chrome 45.0.2454.85• Firefox 40.0.3
JavaScript API から見たPeerConnection と Media 階層
RTCPeerConnection
MediaStream
MediaStream
MediaStream
MediaStreamTrack
MediaStreamTrack
MediaStreamTrack
MediaStreamTrack
videoTracks[] audioTracks[]
DataChannel
N 個
N 個DataChannel
N 個
複数の Media を使う手段• 1 アプリに、複数 PeerConnection– 複数人のケースと同じ
• 1 PeerConnection に、複数 MediaStream– 前回検証した範囲
• 1 MediaStream に、複数 MediaStreamTrack– 今回の中心
WebRTC 周辺 API の微妙なところChrome Firefox
Media Capture and Streamshttp://www.w3.org/TR/mediacapture-streams/ ○ △WebRTC 1.0: Real-time Communication Between Browsershttp://w3c.github.io/webrtc-pc/ △ ○
MediaDevices× ○
MediaStream Recordinghttp://www.w3.org/TR/mediastream-recording/ × ○
Chrome addTrack / removeTrack
• メソッド– MediaStream.addTrack(track)
• video/audio トラックを追加– MediaStream.removeTrack(track)
• video/audio トラックを除去– MediaStream.getVideoTracks() / getAudioTracks()– MediaStream.getTracks()
• イベント– MediaStream.onaddtrack() / onremovetrack ()
• SDP 再交換後、 remoteStream で発火
Offer 側 addTrack() / removeTrack()
Peer BPeer A
createOffer()
Peer-to-Peer
offer SDPsetLocalDescription()
setLocalDescription()answer SDP
setRemoteDescription()
createAnswer()setRemoteDescription()
onaddtrack() 発火
localStream remoteStream remoteStream localStream
addTrack(track)
※onnegotiationneeded() は発火しない※localStream.onaddtrack() は発火しない
onaddtrack() 後、 track の再生まで• onaddtrack(event)
– var track = event.track;• URL.createObjectURL(stream) は、最初のトラックしか対応していない
– × URL.createObjectURL(stream, trackId);– × URL.createObjectURL(stream, trackIndex);– × URL.createObjectURL(track);
• 臨時の MedaiSteram を生成して利用– var tempStream = new MediaStream();– tempStream.addTrack(track);– video.src = window.URL.createObjectURL(tempStream)
Answer 側 addTrack() / removeTrack()
Peer BPeer A
createOffer()
Peer-to-Peer
offer SDPsetLocalDescription()
setLocalDescription()answer SDP
setRemoteDescription()
createAnswer()setRemoteDescription()
onaddtrack() 発火
localStream remoteStream remoteStream localStream
addTrack(track)
※onnegotiationneeded() は発火しない※localStream.onaddtrack() は発火しない
request offer
Firefox addTrack / removeTrack• メソッド
– MediaStream.addTrack() / removeTrack() は無い– mozRTCPeerConnection.addTrack()/removeTrack() がある!
• WebRTC 1.0 の仕様– var sender = peerConnection.addTrack(track, stream);
• sender: RTCRtpSender– peerConnection.removeTrack(sender);
• イベント: addTrack() 側– mozRTCPeerConnection.onnegotiationneeded() 発火
• イベント:相手側– SDP 再交換後 → mozRTCPeerConnection.onaddstream() 発火
• 相手には、新たな mediastream として見える → multi-stream• ※ これって、 Unified Plan と関係してます??
Offer 側 addTrack()
Peer BPeer A
createOffer()
Peer-to-Peer
offer SDPsetLocalDescription()
setLocalDescription()answer SDP
setRemoteDescription()
createAnswer()setRemoteDescription()
onnetosiationneeded () 発火
localStream1 localStream2 remoteStream2 remoteStream1
addTrack(track, localStream2)
onaddstream () 発火remoteStream2 受け取り
Answer 側 addTrack()Peer BPeer A
createOffer()
Peer-to-Peer
offer SDPsetLocalDescription()
setLocalDescription()answer SDP
setRemoteDescription()
createAnswer()setRemoteDescription()
onnetosiationneeded () 発火
localStream1localStream2remoteStream2remoteStream1
addTrack(track, localStream2)
onaddstream () 発火 remoteStream2 受け取り
request offer
Firefox addTrack / removeTrack• 嬉しいところ
– 別の mediastream になるので、そのまま URL.createObjectURL() 使える– ※ 逆に、テンポラリーの MediaStream が作れない
• var temp = new MediaStream() // コンストラクター呼べない( protected)
• 気になるところ– Answer 側から removeTrack() で SDP 交換– Offer 側で serRemoteDescription(answer) 後、エラー発生
setRemoteDescription(answer) ERROR: DOMException [InvalidSessionDescriptionError: "Invalid description, no ice-ufrag attribute"code: 0nsresult: 0x0]
– ※Firefox Nightly 43.0a1 では OK– ※Firefox 41.0 では OK 。ただし繰り返していると no ice-uflag エラー発生
RTCPeerConnection
MediaStream
MediaStreamTrack MediaStreamTrack
addTrack() removeTrack() onaddtrack()onremovetrack()
RTCPeerConnection
MediaStream
Peer-to-Peer
RTCPeerConnection
MediaStreamTrack MediaStreamTrack
addTrack()removeTrack()
onaddstream()onremovestream()
RTCPeerConnection
MediaStream
Peer-to-Peer
Chrome multi-stream
FirefoxWebRTC 1.0
RTCPeerConnection
MediaStream
addStream() removeStream()
onaddstream()onremovestream()
RTCPeerConnection
MediaStream
Peer-to-PeerChrome multi-track
拡大: Chrome の場合 (stream)RTCPeerConnection
MediaStream
addStream()removeStream()
onaddstream()onremovestream()
RTCPeerConnection
MediaStream
Peer-to-Peer
拡大: Chrome の場合 (track)RTCPeerConnection
MediaStream
MediaStreamTrackMediaStreamTrack
addTrack()removeTrack() onaddtrack()
onremovetrack()
RTCPeerConnection
MediaStream
Peer-to-Peer
拡大: Firefox の場合RTCPeerConnection
MediaStreamTrack MediaStreamTrack
addTrack()removeTrack()
onaddstream()onremovestream()
RTCPeerConnection
MediaStream
Peer-to-Peer
おまけ: Firefox replaceTrackvar sender1 = mozRTCPeerConnection.addTrack(track1, stream1);sender1.replaceTrack(track2).then(function() { console.log('replaced'); }); // track2※ は、 PeerConnection に未接続でなければならない
Thank you!