mac app から webrtc の DataChannel でやりとりをする
環境
- osx 10.10.3
- xcode 6.3.2
- webrtc の revision b444b3f0ff095fce497c403aa8149f15ce2f3ea9
- chrome 43.0.2357.81
webrtc を build する
- iOS - WebRTC の通りに build する。
- How to get started with WebRTC and iOS without wasting 10 hours of your life | Ninjanetic Design を参考に libtool を使ってまとめたりする。
xcode の設定
- 上の記事を参考に必用なライブラリ、framework を追加する
src/talk/app/webrtc/objc/public/*.h"
の header を見れるようにする- 下の sample は swift なので Objective-C Bridging Header に指定したファイルに上の header をひと通り import する ( RTCEAGLVideoView.h は ios 用 )
Demo App
src/talk/examples/objc/AppRTCDemo
にサンプルアプリのコードがある
DataChannel を使う
長いので mac app 側から繋ぐ時に必用なところを抜粋する。
RTCPeerConnectionFactory.initializeSSL()
を最初に呼んでおく必用がある。
接続を開始する
let ices = [ RTCICEServer(URI: NSURL(string: "stun:stun.l.google.com:19302")!, username: "", password: ""), ] let optional = [ RTCPair(key: "DtlsSrtpKeyAgreement", value: "true") ] conn = factory.peerConnectionWithICEServers( ices, constraints: RTCMediaConstraints(mandatoryConstraints: [], optionalConstraints: optional), delegate: self ) let channelinit = RTCDataChannelInit() datachannel = conn.createDataChannelWithLabel("...", config: channelinit) datachannel.delegate = self conn.createOfferWithDelegate( self, constraints: RTCMediaConstraints(mandatoryConstraints: [ RTCPair(key: "OfferToReceiveAudio", value: "false"), RTCPair(key: "OfferToReceiveVideo", value: "false") ], optionalConstraints: nil) )
RTCSessionDescriptionDelegate
func peerConnection(peerConnection: RTCPeerConnection!, didCreateSessionDescription sdp: RTCSessionDescription!, error: NSError!) { dispatch_async(dispatch_get_main_queue(), { if error != nil { // err return } peerConnection.setLocalDescriptionWithDelegate(weakSelf, sessionDescription: sdp) // send sdp to signaling server }) }
RTCPeerConnectionDelegate
func peerConnection(peerConnection: RTCPeerConnection!, gotICECandidate candidate: RTCICECandidate!) { dispatch_async(dispatch_get_main_queue(), { // send candidate to signaling server }) }
Signaling Server からのデータの受信
func receiveMessage(msg SignalMessage) { switch msg.type { case .Anseer: let sessionDescription = RTCSessionDescription(type: msg.answer.type, sdp: msg.answer.sdp) conn.setRemoteDescriptionWithDelegate(self, sessionDescription: sessionDescription) case .ICE let candidate = RTCICECandidate(mid: msg.candidate.mid, index: msg.candidate.index, sdp: msg.candidate.sdp) conn.addICECandidate(candidate) default: break } }
Data Channel 経由で書き込みを行う
let data = "...".dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! let buf = RTCDataBuffer(data: data, isBinary: false) datachannel.sendData(buf)
RTCDataChannelDelegate
func channel(channel: RTCDataChannel!, didReceiveMessageWithBuffer buffer: RTCDataBuffer!) { if buffer.isBinary { return } let str = NSString(data: buffer.data, encoding: NSUTF8StringEncoding) println(str) }