WebRTC data channel not connecting or no callbacks

2019-07-16 05:22发布

问题:

In trying to establish and WebRTC data channel using the Objective C API, I can't get any of the RTCDataChannelDelegate callbacks to actually catch. Everything appears to go fine regarding the peer connection, but I only get to a point where the peer connection stream has been added successfully.

My steps are roughly:

Create offer:

    _channel = [_connection createDataChannelWithLabel: @"offer-1"
                                                config: [[RTCDataChannelInit alloc] init]];
    _channel.delegate = _stateMachine;
   [_connection createOfferWithDelegate: _stateMachine constraints: [[RTCMediaConstraints alloc] init]];

The SDP of client 1 is sent to client 2 where an answer is created:

    [_connection setRemoteDescriptionWithDelegate: _stateMachine sessionDescription: [[RTCSessionDescription alloc] initWithType: @"offer" sdp: sdp]];
    [_connection createAnswerWithDelegate: _stateMachine constraints: [[RTCMediaConstraints alloc] init]];

The SDP of client 2 is sent back to client 1:

    [_connection setRemoteDescriptionWithDelegate: _stateMachine sessionDescription: [[RTCSessionDescription alloc] initWithType: @"answer" sdp: sdp]];

After that I get the media stream being added with signaling stable. Previously, during my POC, I was able to get the data channel callbacks but I'm not quite sure what I'm missing here.

Here is the peer connection setup:

    RTCPeerConnectionFactory* _cfactory = [[RTCPeerConnectionFactory alloc] init];

    NSArray* mandatory = @[
                           [[RTCPair alloc] initWithKey:@"DtlsSrtpKeyAgreement" value:@"true"],
                           [[RTCPair alloc] initWithKey:@"internalSctpDataChannels" value:@"true"],
                           ];

    RTCMediaConstraints* pcConstraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints: mandatory
                                                                               optionalConstraints: nil];
    RTCICEServer* server = [[RTCICEServer alloc] initWithURI:[NSURL URLWithString:@"stun:stun.l.google.com:19302"]
                                                    username: @""
                                                    password: @""];
    NSArray* servers = @[server];

    _connection = [_cfactory peerConnectionWithICEServers: servers
                                              constraints: pcConstraints
                                                 delegate: _stateMachine];

My state machine implements the following with all methods present:

@protocol DelegateAggregator
    <RTCPeerConnectionDelegate, RTCSessionDescriptionDelegate, RTCDataChannelDelegate, RTCStatsDelegate>
@end

Is there something I'm missing here? It seems the channel is being established and a media stream is added (I only want data), but without any of the callbacks. Can I enable more logging? Any help would be much appreciated!

回答1:

So it turns out that the key error in how I was structuring my answer was in the callback to initiate the SDP send to client 1. I was waiting for the session created callback to the delegate to send my answer back to client 1. As it turns out, this is too early, and the candidate gathering hasn't finished. I have callbacks setup in the delegate to attach to which looked like this:

//WRONG
_tunnel.stateMachine.peerConnectionSessionCallback = ^(RTCPeerConnection* peerConnection, RTCSessionDescription* sdp, NSError* error) {
        SessionAnswer* answer = [[SessionAnswer alloc] init];
        answer.sdp = [sdp description];

        [queueManager sendEvent: answer];
    };

The correct way is to wait for this event:

_tunnel.stateMachine.peerConnectionICEGatheringCallback = ^(RTCPeerConnection* peerConnection, RTCICEGatheringState newState) {
        if (newState == RTCICEGatheringComplete) {
            SessionAnswer* answer = [[SessionAnswer alloc] init];
            answer.sdp = [[peerConnection localDescription] description];

            [queueManager sendEvent: answer];
        }
    };

Once I structured it this way, the data channel callbacks fired as expected.



回答2:

DtlsSrtpKeyAgreement and internalSctpDataChannels need to be put into the optional constraints instead of Mandatory.

To set up a data channel, I put RtpDataChannels in optional as well.