mac app から webrtc の DataChannel でやりとりをする

環境

  • osx 10.10.3
  • xcode 6.3.2
  • webrtc の revision b444b3f0ff095fce497c403aa8149f15ce2f3ea9
  • chrome 43.0.2357.81

webrtc を build する

  1. iOS - WebRTC の通りに build する。
  2. How to get started with WebRTC and iOS without wasting 10 hours of your life | Ninjanetic Design を参考に libtool を使ってまとめたりする。

xcode の設定

  1. 上の記事を参考に必用なライブラリ、framework を追加する
  2. src/talk/app/webrtc/objc/public/*.h" の header を見れるようにする
  3. 下の 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)
    }