ICE соединение не удается в WebRTC - PullRequest
0 голосов
/ 25 февраля 2019

Мы пытаемся соединить браузер (клиент) с библиотекой aiortc (сервер, который отправляет один видеопоток).В настоящее время соединение успешно установлено (по сигналу состояние стабильное).Однако медиа-соединение никогда не устанавливается, так как ICE-соединение не удается.Два хоста находятся в одной локальной сети, и прямое соединение было проверено.Используется STUN-сервер: stun.l.google.com:19302.

Регистрируются следующие серверы:

DEBUG:asyncio:Using selector: EpollSelector

<RTCSessionDescription is received>

DEBUG:ice:Connection(0) protocol(0) connection_made(<_SelectorDatagramTransport fd=11 read=idle write=<idle, bufsize=0>>)
DEBUG:ice:Connection(0) protocol(0) > ('66.102.1.127', 19302) Message(message_method=Method.BINDING, message_class=Class.REQUEST, transaction_id=b'\xb1\x1f\xdek(\x9c\x10\xe8\x86\xd1Wn')
DEBUG:ice:Connection(0) protocol(0) < ('66.102.1.127', 19302) Message(message_method=Method.BINDING, message_class=Class.RESPONSE, transaction_id=b'\xb1\x1f\xdek(\x9c\x10\xe8\x86\xd1Wn')

<RTCSessionDescription is sent>

<candidate is received>

Raw messages:
SDP offer:
v=0
o=- 7142951019689507792 2 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 97 98 99 100 101 102 123 127 122 125 107 108 109 124
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:A5nH
a=ice-pwd:P0LIjOkkOl/wTtup5n1JA1mC
a=ice-options:trickle
a=fingerprint:sha-256 E3:8E:87:44:E8:D3:A7:02:C0:70:EA:D8:7F:84:F6:80:17:42:33:07:D8:C3:5D:44:FF:DC:25:4C:68:7E:09:19
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=extmap:7 http://www.webrtc.org/experiments/rtp-hdrext/video-content-type
a=extmap:8 http://www.webrtc.org/experiments/rtp-hdrext/video-timing
a=extmap:10 http://tools.ietf.org/html/draft-ietf-avtext-framemarking-07
a=recvonly
a=rtcp-mux
a=rtcp-rsize
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 goog-remb
a=rtcp-fb:96 transport-cc
a=rtcp-fb:96 ccm fir
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:98 VP9/90000
a=rtcp-fb:98 goog-remb
a=rtcp-fb:98 transport-cc
a=rtcp-fb:98 ccm fir
a=rtcp-fb:98 nack
a=rtcp-fb:98 nack pli
a=fmtp:98 profile-id=0
a=rtpmap:99 rtx/90000
a=fmtp:99 apt=98
a=rtpmap:100 H264/90000
a=rtcp-fb:100 goog-remb
a=rtcp-fb:100 transport-cc
a=rtcp-fb:100 ccm fir
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=fmtp:100 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:102 H264/90000
a=rtcp-fb:102 goog-remb
a=rtcp-fb:102 transport-cc
a=rtcp-fb:102 ccm fir
a=rtcp-fb:102 nack
a=rtcp-fb:102 nack pli
a=fmtp:102 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42001f
a=rtpmap:123 rtx/90000
a=fmtp:123 apt=102
a=rtpmap:127 H264/90000
a=rtcp-fb:127 goog-remb
a=rtcp-fb:127 transport-cc
a=rtcp-fb:127 ccm fir
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=fmtp:127 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f
a=rtpmap:122 rtx/90000
a=fmtp:122 apt=127
a=rtpmap:125 H264/90000
a=rtcp-fb:125 goog-remb
a=rtcp-fb:125 transport-cc
a=rtcp-fb:125 ccm fir
a=rtcp-fb:125 nack
a=rtcp-fb:125 nack pli
a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01f
a=rtpmap:107 rtx/90000
a=fmtp:107 apt=125
a=rtpmap:108 red/90000
a=rtpmap:109 rtx/90000
a=fmtp:109 apt=108
a=rtpmap:124 ulpfec/90000

SDP answer:
v=0
o=- 3760099490 3760099490 IN IP4 0.0.0.0
s=-
t=0 0
a=group:BUNDLE video
a=msid-semantic:WMS *
m=video 36695 UDP/TLS/RTP/SAVPF 96 97 100 101 127 122
c=IN IP4 147.175.160.240
a=sendonly
a=extmap:3 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=mid:video
a=msid:25c4a009-f81c-4fe7-b811-a39c525da778 6ffba6fa-08fb-401f-9555-8df85942bd71
a=rtcp:9 IN IP4 0.0.0.0
a=rtcp-mux
a=ssrc-group:FID 461163217 873864728
a=ssrc:461163217 cname:{af4834d3-8db4-41cc-a9cd-6565cb8d82bd}
a=ssrc:873864728 cname:{af4834d3-8db4-41cc-a9cd-6565cb8d82bd}
a=rtpmap:96 VP8/90000
a=rtcp-fb:96 nack
a=rtcp-fb:96 nack pli
a=rtcp-fb:96 goog-remb
a=rtpmap:97 rtx/90000
a=fmtp:97 apt=96
a=rtpmap:100 H264/90000
a=rtcp-fb:100 nack
a=rtcp-fb:100 nack pli
a=rtcp-fb:100 goog-remb
a=fmtp:100 packetization-mode=1;level-asymmetry-allowed=1;profile-level-id=42001f
a=rtpmap:101 rtx/90000
a=fmtp:101 apt=100
a=rtpmap:127 H264/90000
a=rtcp-fb:127 nack
a=rtcp-fb:127 nack pli
a=rtcp-fb:127 goog-remb
a=fmtp:127 packetization-mode=1;level-asymmetry-allowed=1;profile-level-id=42e01f
a=rtpmap:122 rtx/90000
a=fmtp:122 apt=127
a=candidate:a2cdfa74ef4f12d00d150bfa588cf805 1 udp 2130706431 147.175.160.240 36695 typ host
a=candidate:237395b2276e331724a06e8dbed92f44 1 udp 1694498815 147.175.160.240 36695 typ srflx raddr 147.175.160.240 rport 36695
a=end-of-candidates
a=ice-ufrag:IHJz
a=ice-pwd:RNwQMxbAm2EjNIBxklFZKd
a=fingerprint:sha-256 9B:BB:E0:63:DE:5D:BC:1F:CC:A2:FA:FA:0B:29:EB:F1:46:24:D6:A4:E7:9C:B3:C1:50:9D:A3:FB:83:EC:74:2D
a=setup:active

{"candidate":"candidate:1963203886 1 udp 2113937151 147.175.160.205 36583 typ host generation 0 ufrag A5nH network-cost 999","sdpMid":"video","sdpMLineIndex":0,"type":"candidate"}

Код сервера:

class VideoImageTrack(VideoStreamTrack):
    def __init__(self):
        super().__init__()

    async def recv(self):
        pts, time_base = await self.next_timestamp()
        # create frame
        return frame

async def run(pc, recorder, signaling, session_id):
    def add_tracks():
        pc.addTrack(VideoImageTrack())

    # consume signaling
    while True:
        obj = signaling.receive()
        if isinstance(obj, RTCSessionDescription):
            await pc.setRemoteDescription(obj)
            await recorder.start()
            if obj.type == 'offer':
                # send answer
                add_tracks()
                await pc.setLocalDescription(await pc.createAnswer())
                signaling.send(pc.localDescription)
        elif isinstance(obj, RTCIceCandidate):
            pc.addIceCandidate(obj)
        else:
            print('Exiting')
            break

def livestream(session_id,config):
    # create signaling and peer connection
    signaling = Signaling()
    pc = RTCPeerConnection()
    # create media sink
    recorder = MediaBlackhole()
    # run event loop
    loop = asyncio.new_event_loop()
    asyncio.set_event_loop(loop)
    try:
        loop.run_until_complete(run(
            pc=pc,
            recorder=recorder,
            signaling=signaling,
            session_id=session_id))
    except KeyboardInterrupt:
        pass
    finally:
        loop.run_until_complete(recorder.stop())
        loop.run_until_complete(pc.close())

Внешний интерфейскод (важные части):

var configuration = { iceServers: [
      {urls: 'stun:stun.l.google.com:19302'}]
};
this.pc = new RTCPeerConnection(configuration);


const offerOptions = {
      offerToReceiveVideo: 1,
      offerToReceiveAudio: 0
};

let offer = this.pc.createOffer(offerOptions);
offer.then(async value => {
  await this.pc.setLocalDescription(value);
  this.connection.send(JSON.stringify(value))
});


this.connection.onmessage = async event => {
let data = JSON.parse(event.data);
if (data) {
    if (data.type === 'offer') {
      await this.pc.setRemoteDescription(data);
      await this.pc.setLocalDescription(await this.pc.createAnswer());
      this.connection.send({ 'desc': this.pc.localDescription }.toString());
    } else if (data.type === 'answer') {
      await this.pc.setRemoteDescription(data);
    }
  }
};

this.pc.onnegotiationneeded = async () => {
  await this.pc.setLocalDescription(await this.pc.createOffer());
  this.connection.send({ 'desc': this.pc.localDescription }.toString());
};

this.pc.onicecandidate = (event) => {
    if (event.candidate !== null) {
      let data = JSON.parse(JSON.stringify(event.candidate));
      data['type'] = 'candidate';
      this.connection.send(JSON.stringify(data));
    }
};

1 Ответ

0 голосов
/ 10 марта 2019

Было несколько проблем с нашей реализацией:

  1. удалил асинхронные вызовы со стороны сервера - тогда некоторые сопрограммы aiortc не были выполнены должным образом
  2. отсутствует обработка сообщения типа 'кандидата' вfront-end
  3. неправильный формат сообщения {'desc': this.pc.localDescription} .toString () - должен быть JSON.stringify ({desc: this.pc.localDescription})

Нам удалось исправить все проблемы, поэтому я закрываю этот вопрос.

...