CFSocketSetAddress绑定失败:重新打开流后48

时间:2016-07-08 12:20:43

标签: ios swift streaming

Hello在我的iOS Swift应用程序中我显示了一个实时流。

因此我创建了这个函数来启动流,当加载特定的containerView时调用该流:

func startStream() {

    let masterViewController = self.parentViewController as? MasterViewController

    let ip = RTPTools().findLocalWifiIp()
    print("local IP: \(ip)")

    let view = masterViewController!.streamView
    view.waiting = true

    masterViewController!.receiver = RTPReceiver(localIp: ip, listenPort: 5000)
    masterViewController!.receiver!.delegate = view
    view.setNeedsDisplay()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MasterViewController.decodingFailed(_:)), name: AVSampleBufferDisplayLayerFailedToDecodeNotification, object: self.view.layer)

    Connector.sharedInstance.runLivePreview()

    masterViewController?.showStreamView()
}

我在viewDidAppear函数中调用此方法并设置通知函数如下:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)

    NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(InformationsViewController.restartStream), name: UIApplicationWillEnterForegroundNotification, object: nil)
    NSNotificationCenter.defaultCenter().addObserver(self, selector:#selector(InformationsViewController.clearStream), name: UIApplicationWillResignActiveNotification, object: nil)

    startStream()
}

clearstream和restartStream函数如下所示:

func clearStream() {
    let masterViewController = self.parentViewController as? MasterViewController
    masterViewController!.receiver = nil

    Connector.sharedInstance.stopLivePreview()
}

func restartStream() {
    let masterViewController = self.parentViewController as? MasterViewController

    let ip = RTPTools().findLocalWifiIp()
    print("local IP: \(ip)")

    let view = masterViewController!.streamView
    view.waiting = true

    masterViewController!.receiver = RTPReceiver(localIp: ip, listenPort: 5000)
    masterViewController!.receiver!.delegate = view
    view.setNeedsDisplay()

    let videoLayer = view.layer as! AVSampleBufferDisplayLayer
    videoLayer.flushAndRemoveImage()

    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MasterViewController.decodingFailed(_:)), name: AVSampleBufferDisplayLayerFailedToDecodeNotification, object: self.view.layer)

    Connector.sharedInstance.runLivePreview()

    masterViewController?.showStreamView()
}

问题是,当我在流运行时单击主页按钮然后返回应用程序时,一切都会启动并正常工作。但我得到CFSocketSetAddress绑定失败:48错误,当我将视图切换到另一个视图,然后切换回流运行的视图。

RTPReceiver的实现如下:

@implementation RTPReceiver

- (id) initWithLocalIp:(NSString*)ip listenPort:(uint16_t)port {
    self = [super init];
    if (!self) {
        return nil;
    }
    self.localIp = ip;
    self.listenPort = port;

    //create socket
    CFSocketContext socketContext = {0, (__bridge void*)self, NULL, NULL, NULL};
    CFSocketRef socket = CFSocketCreate(NULL, PF_INET, SOCK_DGRAM, IPPROTO_UDP,
                              kCFSocketDataCallBack , MySocketCallback, &socketContext);
    NSAssert(socket, @"Socket creation failed");
    self.socket = socket;
    CFRelease(socket);

    //set address
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_len = sizeof(addr);
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr([self.localIp cStringUsingEncoding:NSASCIIStringEncoding]);
    addr.sin_port = htons(self.listenPort);
    NSData* address = [NSData dataWithBytes:&addr length: sizeof(addr)];

    // HERE IS THE ERROR
    CFSocketError sockErr = CFSocketSetAddress(self.socket, (CFDataRef) address);
    NSAssert(sockErr == kCFSocketSuccess,@"Set socket address failed");

    //add to run loop
    CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, self.socket, 0);
    CFRunLoopAddSource(CFRunLoopGetMain(), source, kCFRunLoopCommonModes);
    CFRelease(source);
    return self;
}

我不明白为什么我会收到此错误,而我正在执行相同的流程来启动流。任何人都可以帮助我吗?

1 个答案:

答案 0 :(得分:0)

我也找到了解决方案。

为什么不使用下面而不是CFSocketSetAddress

    if (0 != (err = bind(sock, (struct sockaddr *)&addr, sizeof(addr)))) {
        NSLog(@"Bind error");
        return false;
    }

因为在文件中,

  

此函数通过调用bind来绑定套接字,如果套接字支持它,则通过使用256的积压调用listen来配置要监听的套接字。

使用 bind 对我有用,现在我也找到了使用CFSocketSetAddress的方法。