2017-03-10 1 views
4

webrtc setup을 사용하여 "one to many"(최대 3 개 장치)를 만들고 싶습니다. 내 주 장치 인 하나의 장치가 있습니다. 다른 장치가 해당 장치에 연결 중입니다. 당신은 무뚝뚝한 얘기를 생각할 수 있습니다. 하나의 기기가 연결 대상입니다.일대일 webrtc

1 대 1 연결로 작동하는이 코드가 있습니다.

import AVFoundation 
import UIKit 
import WebRTC 
import SocketIO 
import CoreTelephony 
import ReachabilitySwift 

let TAG = "ViewController" 
let AUDIO_TRACK_ID = TAG + "AUDIO" 
let LOCAL_MEDIA_STREAM_ID = TAG + "STREAM" 

class ViewController: UIViewController, RTCPeerConnectionDelegate, RTCDataChannelDelegate { 

    var mediaStream: RTCMediaStream! 
    var localAudioTrack: RTCAudioTrack! 
    var remoteAudioTrack: RTCAudioTrack! 
    var dataChannel: RTCDataChannel! 
    var dataChannelRemote: RTCDataChannel! 

    var roomName: String! 


    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 

     initWebRTC(); 
     sigConnect(wsUrl: "http://192.168.1.69:3000"); 

     localAudioTrack = peerConnectionFactory.audioTrack(withTrackId: AUDIO_TRACK_ID) 
     mediaStream = peerConnectionFactory.mediaStream(withStreamId: LOCAL_MEDIA_STREAM_ID) 
     mediaStream.addAudioTrack(localAudioTrack) 
    } 

    func getRoomName() -> String { 
     return (roomName == nil || roomName.isEmpty) ? "_defaultroom": roomName; 
    } 

    // webrtc 
    var peerConnectionFactory: RTCPeerConnectionFactory! = nil 
    var peerConnection: RTCPeerConnection! = nil 
    var mediaConstraints: RTCMediaConstraints! = nil 

    var socket: SocketIOClient! = nil 
    var wsServerUrl: String! = nil 
    var peerStarted: Bool = false 

    func initWebRTC() { 
     RTCInitializeSSL() 
     peerConnectionFactory = RTCPeerConnectionFactory() 

     let mandatoryConstraints = ["OfferToReceiveAudio": "true", "OfferToReceiveVideo": "false"] 
     let optionalConstraints = [ "DtlsSrtpKeyAgreement": "true", "RtpDataChannels" : "true", "internalSctpDataChannels" : "true"] 


     mediaConstraints = RTCMediaConstraints.init(mandatoryConstraints: mandatoryConstraints, optionalConstraints: optionalConstraints) 

    } 

    func connect() { 
     if (!peerStarted) { 
      sendOffer() 
      peerStarted = true 
     } 
    } 

    func hangUp() { 
     sendDisconnect() 
     stop() 
    } 

    func stop() { 
     if (peerConnection != nil) { 
      peerConnection.close() 
      peerConnection = nil 
      peerStarted = false 
     } 
    } 

    func prepareNewConnection() -> RTCPeerConnection { 
     var icsServers: [RTCIceServer] = [] 

     icsServers.append(RTCIceServer(urlStrings: ["stun:stun.l.google.com:19302"], username:"",credential: "")) 

     let rtcConfig: RTCConfiguration = RTCConfiguration() 
     rtcConfig.tcpCandidatePolicy = RTCTcpCandidatePolicy.disabled 
     rtcConfig.bundlePolicy = RTCBundlePolicy.maxBundle 
     rtcConfig.rtcpMuxPolicy = RTCRtcpMuxPolicy.require 
     rtcConfig.iceServers = icsServers; 

     peerConnection = peerConnectionFactory.peerConnection(with: rtcConfig, constraints: mediaConstraints, delegate: self) 
     peerConnection.add(mediaStream); 

     let tt = RTCDataChannelConfiguration(); 
     tt.isOrdered = false;   


     self.dataChannel = peerConnection.dataChannel(forLabel: "testt", configuration: tt) 

     self.dataChannel.delegate = self 
     print("Make datachannel") 

     return peerConnection; 
    } 

    // RTCPeerConnectionDelegate - begin [ /////////////////////////////////////////////////////////////////////////////// 


    /** Called when the SignalingState changed. */ 
    public func peerConnection(_ peerConnection: RTCPeerConnection, didChange stateChanged: RTCSignalingState){ 
     print("signal state: \(stateChanged.rawValue)") 
    } 


    /** Called when media is received on a new stream from remote peer. */ 
    public func peerConnection(_ peerConnection: RTCPeerConnection, didAdd stream: RTCMediaStream){ 
     if (peerConnection == nil) { 
      return 
     } 

     if (stream.audioTracks.count > 1) { 
      print("Weird-looking stream: " + stream.description) 
      return 
     } 
    } 

    /** Called when a remote peer closes a stream. */ 
    public func peerConnection(_ peerConnection: RTCPeerConnection, didRemove stream: RTCMediaStream){} 


    /** Called when negotiation is needed, for example ICE has restarted. */ 
    public func peerConnectionShouldNegotiate(_ peerConnection: RTCPeerConnection){} 


    /** Called any time the IceConnectionState changes. */ 
    public func peerConnection(_ peerConnection: RTCPeerConnection, didChange newState: RTCIceConnectionState){} 


    /** Called any time the IceGatheringState changes. */ 
    public func peerConnection(_ peerConnection: RTCPeerConnection, didChange newState: RTCIceGatheringState){} 


    /** New ice candidate has been found. */ 
    public func peerConnection(_ peerConnection: RTCPeerConnection, didGenerate candidate: RTCIceCandidate){ 


      print("iceCandidate: " + candidate.description) 
      let json:[String: AnyObject] = [ 
       "type" : "candidate" as AnyObject, 
       "sdpMLineIndex" : candidate.sdpMLineIndex as AnyObject, 
       "sdpMid" : candidate.sdpMid as AnyObject, 
       "candidate" : candidate.sdp as AnyObject 
      ] 
      sigSendIce(msg: json as NSDictionary) 

    } 


    /** Called when a group of local Ice candidates have been removed. */ 
    public func peerConnection(_ peerConnection: RTCPeerConnection, didRemove candidates: [RTCIceCandidate]){} 


    /** New data channel has been opened. */ 
    public func peerConnection(_ peerConnection: RTCPeerConnection, didOpen dataChannel: RTCDataChannel){ 
     print("Datachannel is open, name: \(dataChannel.label)") 
     dataChannel.delegate = self 
     self.dataChannelRemote = dataChannel 
    } 



    // RTCPeerConnectionDelegate - end ]///////////////////////////////////////////////////////////////////////////////// 

    public func dataChannel(_ dataChannel: RTCDataChannel, didReceiveMessageWith buffer: RTCDataBuffer){ 
     print("iets ontvangen"); 
    } 

    public func dataChannelDidChangeState(_ dataChannel: RTCDataChannel){ 
     print("channel.state \(dataChannel.readyState.rawValue)"); 
    } 


    func sendData(message: String) { 
     let newData = message.data(using: String.Encoding.utf8) 
     let dataBuff = RTCDataBuffer(data: newData!, isBinary: false) 
     self.dataChannel.sendData(dataBuff) 
    } 

    func onOffer(sdp:RTCSessionDescription) { 
     print("on offer shizzle") 

     setOffer(sdp: sdp) 
     sendAnswer() 
     peerStarted = true; 
    } 

    func onAnswer(sdp:RTCSessionDescription) { 
     setAnswer(sdp: sdp) 
    } 

    func onCandidate(candidate:RTCIceCandidate) { 
     peerConnection.add(candidate) 
    } 

    func sendSDP(sdp:RTCSessionDescription) { 
     print("Converting sdp...") 
     let json:[String: AnyObject] = [ 
      "type" : sdp.type.rawValue as AnyObject, 
      "sdp" : sdp.sdp.description as AnyObject 
     ] 

     sigSend(msg: json as NSDictionary); 
    } 

    func sendOffer() { 
     peerConnection = prepareNewConnection(); 
     peerConnection.offer(for: mediaConstraints) { (RTCSessionDescription, Error) in 

      if(Error == nil){ 
       print("send offer") 

       self.peerConnection.setLocalDescription(RTCSessionDescription!, completionHandler: { (Error) in 
        print("Sending: SDP") 
        print(RTCSessionDescription as Any) 
        self.sendSDP(sdp: RTCSessionDescription!) 
       }) 
      } else { 
       print("sdp creation error: \(Error)") 
      } 

     } 
    } 


    func setOffer(sdp:RTCSessionDescription) { 
     if (peerConnection != nil) { 
      print("peer connection already exists") 
     } 
     peerConnection = prepareNewConnection(); 
     peerConnection.setRemoteDescription(sdp) { (Error) in 

     } 
    } 

    func sendAnswer() { 
     print("sending Answer. Creating remote session description...") 
     if (peerConnection == nil) { 
      print("peerConnection NOT exist!") 
      return 
     } 

     peerConnection.answer(for: mediaConstraints) { (RTCSessionDescription, Error) in 
      print("ice shizzle") 

      if(Error == nil){ 
       self.peerConnection.setLocalDescription(RTCSessionDescription!, completionHandler: { (Error) in 
        print("Sending: SDP") 
        print(RTCSessionDescription as Any) 
        self.sendSDP(sdp: RTCSessionDescription!) 
       }) 
      } else { 
       print("sdp creation error: \(Error)") 
      } 

     } 
    } 

    func setAnswer(sdp:RTCSessionDescription) { 
     if (peerConnection == nil) { 
      print("peerConnection NOT exist!") 
      return 
     } 

     peerConnection.setRemoteDescription(sdp) { (Error) in 
      print("remote description") 
     } 
    } 

    func sendDisconnect() { 
     let json:[String: AnyObject] = [ 
      "type" : "user disconnected" as AnyObject 
     ] 
     sigSend(msg: json as NSDictionary); 
    } 

    // websocket related operations 
    func sigConnect(wsUrl:String) { 
     wsServerUrl = wsUrl; 

     print("connecting to " + wsServerUrl) 
     socket = SocketIOClient(socketURL: NSURL(string: wsServerUrl)! as URL) 

     socket.on("connect") { data in 
      print("WebSocket connection opened to: " + self.wsServerUrl); 
      self.sigEnter(); 
     } 
     socket.on("disconnect") { data in 
      print("WebSocket connection closed.") 
     } 
     socket.on("message") { (data, emitter) in 
      if (data.count == 0) { 
       return 
      } 

      let json = data[0] as! NSDictionary 
      print("WSS->C: " + json.description); 

      let type = json["type"] as! Int 

      if (type == RTCSdpType.offer.rawValue) { 
       print("Received offer, set offer, sending answer...."); 
       let sdp = RTCSessionDescription(type: RTCSdpType(rawValue: type)!, sdp: json["sdp"] as! String) 
       self.onOffer(sdp: sdp); 
      } else if (type == RTCSdpType.answer.rawValue && self.peerStarted) { 
       print("Received answer, setting answer SDP"); 
       let sdp = RTCSessionDescription(type: RTCSdpType(rawValue: type)!, sdp: json["sdp"] as! String) 
       self.onAnswer(sdp: sdp); 
      } else { 
       print("Unexpected websocket message"); 
      } 
     } 

     socket.on("ice") { (data, emitter) in 
      if (data.count == 0) { 
       return 
      } 

      let json = data[0] as! NSDictionary 
      print("WSS->C: " + json.description); 

      let type = json["type"] as! String 


      if (type == "candidate" && self.peerStarted) { 
       print("Received ICE candidate..."); 
       let candidate = RTCIceCandidate(
        sdp: json["candidate"] as! String, 
        sdpMLineIndex: Int32(json["sdpMLineIndex"] as! Int), 
        sdpMid: json["sdpMid"] as? String) 
        self.onCandidate(candidate: candidate); 
      } else { 
       print("Unexpected websocket message"); 
      } 
     } 

     socket.connect(); 
    } 

    func sigRecoonect() { 
     socket.disconnect(); 
     socket.connect(); 
    } 

    func sigEnter() { 
     let roomName = getRoomName(); 
     print("Entering room: " + roomName); 
     socket.emit("enter", roomName); 
    } 

    func sigSend(msg:NSDictionary) { 
     socket.emit("message", msg) 
    } 

    func sigSendIce(msg:NSDictionary) { 
     socket.emit("ice", msg) 
    } 
} 

그래서 나는 동료와 배열이 필요하다고 생각했습니다. 그리고 로컬 오디오가 동일하기 때문에 mediaStream, localAudioTrack 및 dataChannel이 하나의 객체 여야합니다. 이것에 대한 좋은 해결책이 있습니까? 왜냐하면 나는 이것을 올바르게 구현하는 방법을 모르기 때문입니다.

여러 통화 webrtc 설정을 참조하는 다른 질문과 프로젝트를 조사하고 있습니다. 내가 신속한 :)이 리버스 엔지니어링을 시도거야 https://github.com/anoek/webrtc-group-chat-example/blob/master/client.html

:

나는 GitHub의에서이 (웹 사이트)의 WebRTC 설정을 보았다. 어떤 도움이라도 대단히 감사합니다.

+0

3 명의 사용자가 연결되어있는 [WebRTC]의 가능한 복제본 (http://stackoverflow.com/questions/36885362/webrtc-with-3-users-connection) – jib

+0

@jib 아니요, 제 질문은 신속한 것입니다. – da1lbi3

+0

일반 물류처럼 보입니다. 누군가 당신을 위해 그것을 쓰길 원하니? – jib

답변

3

단일 장치가 미디어를 다른 모든 장치로 보내야하는 일대 다 아키텍처에 대해 제안합니다. 이것은 매우 빠른 속도로 끊어집니다 (2-3 개의 장치가 연결되어야하는 것처럼).

그 이유는 업 링크의 용량이 일반적으로 제한되어 있고 그렇지 않은 경우에도 장치가 많은 다른 장치로 많은 양의 데이터를 스트리밍하는 데 정말로 적합하지 않기 때문입니다.

"규모"에서 원하는 것을 수행하려면 미디어를 다른 장치로 라우팅하는 서버 구성 요소를 사용하십시오. 시작 지점은 https://jitsi.org/http://www.kurento.org/입니다.