首页 关于 微信公众号
欢迎关注我的微信公众号

问题处理-过滤信令

bug场景

Anywhere的TVUCC界面和其它设备(TVUPACK,Anywhere)进行viop电话。具体操作是:

现象:没有成功挂断。并且一旦用户离开主页面,在app端就能听到其它T的声音。经过检测,发现app一直保持通话中。

分析原因

通过查看信令服务器的log我们发现:

Anywhere端打电话的逻辑是当收到另一端的response时,创建peerConnection,然后做其余的和打电话相关的操作。

原因归属

发生以上bug的原因归属于三个方面,其中任何一方解决问题都可以避免该bug。具体有:

此时我们只负责处理Anywhere端的问题。处理这种问题其实就是有效信令的过滤。当我们接收到一条信令时,我们是不是应该忽略它。

解决问题

case1:为每一路电话添加状态标记

这是一种非常简单的过滤方法。具体逻辑是:

代码实现:

1) 用一个map保存每一路电话的当前状态。key是电话号码,value是状态(KTVUVoiceState类型)

每一路电话状态KTVUVoiceState的枚举定义:

typedef enum
{
    KTVUVoiceState_unknown = 0,
    KTVUVoiceState_call,
    KTVUVoiceState_disconnect
}KTVUVoiceState;

2) 对map的操作:

#pragma mark --control signaling state of call
- (void)updateSignalingStateWithPhone:(NSString *)phone andState:(KTVUVoiceState)state
{
    log4cplus_warn("WebRTCLog", "%s change state to %d",[phone UTF8String],(int)state);
    [self.signalStateDict setObject:[NSNumber numberWithInt:(int)state] forKey:phone];
}

- (KTVUVoiceState)getSignalingStateOfPhone:(NSString *)phone
{
    NSNumber *state = [self.signalStateDict objectForKey:phone];
    if (state == NULL) {
        return KTVUVoiceState_unknown;
    }
    return (KTVUVoiceState)[state intValue];
}

- (BOOL)shouldDismissThisSignal:(NSString *)phone
{
    KTVUVoiceState state = [self getSignalingStateOfPhone:phone];
    if (state == KTVUVoiceState_disconnect) {
        log4cplus_warn("WebRTCLog", "%s,%s state is KTVUVoiceState_disconnect,dismiss this signal..",__func__,[phone UTF8String]);
        return YES;
    }
    return NO;
}

3) 信令过滤

if (messtype == KSignalingTypeOffer || messtype == KSignalingTypeIce || messtype == KSignalingTypeCallResponse || KSignalingTypeAnswer) {
        
        if ([self shouldDismissThisSignal:callFromNumber]) {
            return;
        }
        
    }

4) 更新每路电话状态:

设置为call状态(收到call_request时)

case KSignalingTypeCallRequest:
        {
            log4cplus_warn("WebRTCLog", "%s,receive call request info, message=%s",__func__,[callFromNumber UTF8String]);
            
            dispatch_queue_t phoneQueue = [self getSerialQueue:callFromNumber];
            dispatch_async(phoneQueue, ^{
                [self updateSignalingStateWithPhone:callFromNumber andState:KTVUVoiceState_call];   // set phone state is call
            });
            
            [self processCallRequestUseMessageData:messageStr andPhoneNumber:callFromNumber];
        }
            break;

设置为call状态(主动打电话时)

- (void)callPhone:(NSString *)phone
{
    log4cplus_warn("WebRTCLog", "%s,call request,data:%s",__func__,[phone UTF8String]);

    NSString *phones = [NSJSONSerialization JSONStringWithJSONObject:@[phone]];
    if (!phones) {
        log4cplus_error("WebRTCLog", "%s,call phone error,phone is null",__func__);
        return;
    }
    _tvuSignal->postCallRequest([phones UTF8String]);
    
    [self updateSignalingStateWithPhone:phone andState:KTVUVoiceState_call];
}

设置为disconnect状态(被动挂电话时–收到disconnect信令)

- (void)processDisconnectPeerUseMessageData:(NSString *)message andPhoneNumber:(NSString *)phoneNumber
{
    self.isEndupCall = YES;
    
    dispatch_queue_t phoneQueue = [self getSerialQueue:phoneNumber];
    dispatch_async(phoneQueue, ^{
        __block RTCPeerConnection *peerConnection = [self getPeerConnectionUsePhoneNumber:phoneNumber];
        
        if (!peerConnection) {
            log4cplus_warn("WebRTCLog", "%s,cancel call...",__func__);
            [self.delegate cancelCallWithTVUWebRTCManager:self];
            return;
        }
        
        if (phoneNumber == self.nowCallFromPhone) {
            self.nowCallFromPhone = NULL;
        }

        usleep(1000*100);
        [self removeElementsFromPeerConnectionsDict:phoneNumber andType:KRemovePeerConnectionTypeDisconnect];
        [peerConnection close];
        [peerConnection stopRtcEventLog];
        peerConnection = nil;
        log4cplus_warn("WebRTCLog", "%s,peerConn close,_peerConn=nil, phone=%s",__func__,[phoneNumber UTF8String]);
        [self.delegate endupCallWithTVUWebRTCManager:self];
    });

}

设置为disconnect状态(主动挂断电话时)

- (void)hangupPhone:(NSString *)phone
{
    log4cplus_warn("WebRTCLog", "%s,hang up phone,phone=%s",__func__,[phone UTF8String]);
    if (phone != NULL) {
        _tvuSignal->postDisconnectpeer([phone UTF8String]);
        [self updateSignalingStateWithPhone:phone andState:KTVUVoiceState_disconnect];
    }
    __block RTCPeerConnection *peerConnection = [self getPeerConnectionUsePhoneNumber:phone];
    if (!peerConnection) {
        log4cplus_error("WebRTCLog", "hang up phone error,phone=%s",[phone UTF8String]);
        return;
    }
    NSArray *streamsArray = peerConnection.localStreams;
    
    if (streamsArray || [streamsArray count] > 0) {
        RTCMediaStream *mediaStream = [peerConnection.localStreams firstObject];
        if (mediaStream) {
            log4cplus_error("WebRTCLog", "%s,remove mediaStream,phone=%s,line=%d",__func__,[phone UTF8String],__LINE__);
//            [peerConnection removeStream:mediaStream];
        }
    }
    
    [peerConnection close];
    [self removeElementsFromPeerConnectionsDict:phone andType:KRemovePeerConnectionTypeEndupCall];
    usleep(1000*100);
    
    [peerConnection stopRtcEventLog];
    peerConnection = nil;
    log4cplus_warn("WebRTCLog", "%s,peerConn=nil,phone=%s,line=%d",__func__,[phone UTF8String],__LINE__);
}

Blog

Opinion

Project