0

I am trying to establish one to one peer connection using multipeer connectivity framework. When i am sending invitation to nearby peer that device gets connected(sometime takes long time to get connected), and the peer which has send the request is always taking long time to change its state to connected & once it is connected immediately it is disconnecting from the session. I tried to debug the issue but not found anything, dont know what wrong is happening, please let me know if i am missing anything or any mistake is done in code.

Below given is the code snippet of the same.

MPCHandler.m

#define DidChangeStateNotification @"E_DidChangeStateNotification"
#define DidReceiveDataNotification @"E_DidReceiveDataNotification"
#define DidInviteNotification @"E_DidInvitedNotification"
#define DidReceivedInvetationNotification @"E_DidReceivedInvetationNotification"

static NSString * const EServiceType = @"E-service";

@interface MPCHandler ()
@property AppDelegate *appDelegate;
@end

@implementation MPCHandler

- (void)setupPeerWithDisplayName:(NSString *)displayName {

    self.appDelegate = [[UIApplication sharedApplication] delegate];
    self.peerID = [[MCPeerID alloc] initWithDisplayName:displayName];

    self.connectedPeers = [NSMutableArray array];
    self.foundPeers = [NSMutableArray array];
    self.invitedPeers = [NSMutableArray array];
}

- (void)setupSession {

    self.session = [[MCSession alloc] initWithPeer:self.peerID securityIdentity:nil    encryptionPreference:MCEncryptionNone];
    self.session.delegate = self;
}

- (void)setupBrowser {

    self.browser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.peerID serviceType:EServiceType];
    self.browser.delegate = self;

}

- (void)advertiseSelf:(BOOL)advertise {

    if (advertise) {
        self.advertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.peerID discoveryInfo:nil serviceType:EServiceType];
        self.advertiser.delegate = self;
        [self.advertiser startAdvertisingPeer];

    } else {
        [self.advertiser stopAdvertisingPeer];
        self.advertiser = nil;
    }
}

#pragma MCSessionDelegate methods

- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
    NSDictionary *userInfo = @{ @"peerID": peerID,
                            @"state" : @(state) };

    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:DidChangeStateNotification
                                                        object:nil
                                                      userInfo:userInfo];
    });
}

- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID {
    NSDictionary *userInfo = @{ @"data": data,
                            @"peerID": peerID };

    dispatch_async(dispatch_get_main_queue(), ^{
        [[NSNotificationCenter defaultCenter] postNotificationName:DidReceiveDataNotification
                                                        object:nil
                                                      userInfo:userInfo];
    });
}

- (void)session:(MCSession *)session didReceiveCertificate:(NSArray *)certificate fromPeer:(MCPeerID *)peerID certificateHandler:(void (^)(BOOL))certificateHandler{
certificateHandler(YES);
}

#pragma MCNearbyServiceAdvertiserDelegate methods

    // Incoming invitation request.  Call the invitationHandler block with YES and a valid session  to connect the inviting peer to the session.
 - (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(NSData *)context invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler{


   NSDictionary *info =[NSDictionary dictionaryWithObject:peerID.displayName forKey:@"displayName"];
   NSLog(@"%@ Received Invetation from : %@",self.peerID.displayName,peerID.displayName);

   invitationHandler(YES,self.session);

   [self.connectedPeers addObject:peerID];
   self.invited = NO;

   dispatch_async(dispatch_get_main_queue(), ^{

       [[NSNotificationCenter defaultCenter] postNotificationName:DidReceivedInvetationNotification
                                                        object:nil
                                                      userInfo:info];
   });

} #pragma MCNearbyServiceBrowserDelegate methods

// Found a nearby advertising peer
 - (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:  (NSDictionary *)info{

  //    NSLog(@"Peer : %@ found.",peerID.displayName);

     //    if (![self.peerID isEqual:peerID]) {

     NSLog(@"%@ Found Peer : %@",self.peerID.displayName,peerID.displayName);

    [self.foundPeers addObject:peerID];

     if (![self.connectedPeers containsObject:peerID])
     {
         if ([self.invitedPeers count] == 0 && [self.session.connectedPeers count]==0)
        {

            NSLog(@"%@ Invited Peer : %@",self.peerID.displayName,peerID.displayName);

            [self.invitedPeers addObject:peerID];

            [browser invitePeer:peerID
                       toSession:self.session
                    withContext:[@"Empath" dataUsingEncoding:NSUTF8StringEncoding]
                    timeout:0];

        //            [browser stopBrowsingForPeers];

                   self.invited = YES;

                NSDictionary *userInfo = @{ @"peerID": peerID };

               dispatch_async(dispatch_get_main_queue(), ^{

                    [[NSNotificationCenter defaultCenter] postNotificationName:DidInviteNotification
                                                                object:nil
                                                              userInfo:userInfo];
                });
          }
       }

        //    }
  }

  // A nearby peer has stopped advertising
  - (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID{
      [self.foundPeers removeObject:peerID];
     [self.invitedPeers removeAllObjects];
    [browser startBrowsingForPeers];
  }
 - (void)browser:(MCNearbyServiceBrowser *)browser didNotStartBrowsingForPeers:(NSError *)error
{
      NSLog( @"Unable to start browsing for peers. Error: %@", error );
 }

   ViewController.m

#define DidChangeStateNotification @"E_DidChangeStateNotification"
#define DidReceiveDataNotification @"E_DidReceiveDataNotification"
#define DidInviteNotification @"E_DidInvitedNotification"
#define DidReceivedInvetationNotification @"E_DidReceivedInvetationNotification"

@interface ViewController ()
@property (nonatomic, strong) AppDelegate *appDelegate;
@end

@implementation ViewController

@synthesize txtMessage;
@synthesize tvHistory;
@synthesize btnSend;
@synthesize lblName;

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.appDelegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
//    self.appDelegate.connectedPeers = [NSMutableArray array];
//    self.appDelegate.foundPeers = [NSMutableArray array];

    [self AddObservers];

    [self setUserInteraction:NO];
    [self.lblName setText:@""];
    [self.btnSend setUserInteractionEnabled:NO];
    [self performSelector:@selector(advertisePeer) withObject:nil afterDelay:0.0];
}

-(void) AddObservers{

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(handleReceivedDataWithNotification:)
                                                 name:DidReceiveDataNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(peerChangedStateWithNotification:)
                                                 name:DidChangeStateNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(receivedInvetationWithNotification:)
                                                 name:DidReceivedInvetationNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(peerInvitedWithNotification:)
                                                 name:DidInviteNotification
                                               object:nil];

    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(sessionDidTimeout:)     name:kSessionDidTimeoutNotification object:nil];
}
-(void) advertisePeer{

    [self setUserInteraction:NO];
    [self.lblName setText:@""];
    [self.appDelegate.mpcHandler setupPeerWithDisplayName:[UIDevice currentDevice].name];
    [self.appDelegate.mpcHandler setupSession];
    [self.appDelegate.mpcHandler advertiseSelf:YES];
    [self.btnSend setUserInteractionEnabled:YES];
}

- (IBAction)searchAndConnectPeer:(id)sender{

        [self.lblName setText:@"Searching..."];
        if (self.appDelegate.mpcHandler.session != nil) {
            [[self.appDelegate mpcHandler] setupBrowser];

            [[[self.appDelegate mpcHandler] browser] startBrowsingForPeers];

        }
}

- (IBAction)sendMessage:(id)sender{

    NSString *messageToSend = [txtMessage text];
    NSUInteger len = 0;
    if ([messageToSend length]) {

        NSData *messageAsData = [messageToSend dataUsingEncoding:NSUTF8StringEncoding];
        NSError *error;

        [self.appDelegate.mpcHandler.session sendData:messageAsData
                                          toPeers:self.appDelegate.mpcHandler.session.connectedPeers
                                         withMode:MCSessionSendDataReliable
                                            error:&error];

        // If any error occurs, just log it.
        // Otherwise set the following couple of flags to YES, indicating that the current player is the creator
        // of the game and a game is in progress.
         len = [[tvHistory text] length];
         if (error != nil) {
            NSLog(@"%@", [error localizedDescription]);
           [self.tvHistory setText:[NSString stringWithFormat:@"%@",[error localizedDescription]]];
        } else{

            NSString *history = [NSString stringWithFormat:@"Me : %@\n\n",messageToSend];
            [self.tvHistory setText:[self.tvHistory.text stringByAppendingString:history]];
        }
    }

     [self.txtMessage setText:@""];
    [self.tvHistory scrollRangeToVisible:NSMakeRange([self.tvHistory.text length], len)];
}
- (void)peerInvitedWithNotification:(NSNotification *)notification{
    [self setUserInteraction:NO];
     MCPeerID *peerID = [[notification userInfo] objectForKey:@"peerID"];
    [self.lblName setText:[NSString stringWithFormat:@"Connecting to %@...",peerID.displayName]];
}
- (void)receivedInvetationWithNotification:(NSNotification *)notification{
    [self setUserInteraction:YES];
    NSString *name = [[notification userInfo] objectForKey:@"displayName"];
    [self.lblName setText:[NSString stringWithFormat:@"Connected : %@",name]];
}
- (void)peerChangedStateWithNotification:(NSNotification *)notification {
    // Get the state of the peer.

    int state = [[[notification userInfo] objectForKey:@"state"] intValue];
    MCPeerID *peerID = [[notification userInfo] objectForKey:@"peerID"];

    // We care only for the Connected and the Not Connected states.
    // The Connecting state will be simply ignored.
    if (state == MCSessionStateConnected) {

        // We'll just display all the connected peers (players) to the text view.
        NSString *allPlayers = @"Connected : ";

        allPlayers = [allPlayers stringByAppendingString:[NSString tringWithFormat:@"%@",peerID.displayName]];
        [self.lblName setText:allPlayers];
        [self setUserInteraction:YES];
        NSLog(@"%@...",allPlayers);
//        // Fire up the timer upon first event
//        if(!_idleTimer) {
//            [self resetIdleTimer];
//        }

    }else if (state == MCSessionStateConnecting){

        [self setUserInteraction:NO];
        [self.lblName setText:[NSString stringWithFormat:@"Connecting to %@...",peerID.displayName]];
        NSLog(@"Connecting %@...",peerID.displayName);

    }else if (state == MCSessionStateNotConnected){

        NSLog(@"Disconnected %@...",peerID.displayName);
//        [self sessionDidTimeout:nil];
    }
}
-(void) setUserInteraction:(BOOL)enabled{
    [self.btnSend setUserInteractionEnabled:enabled];
    [self.txtMessage setUserInteractionEnabled:enabled];
}
- (void)handleReceivedDataWithNotification:(NSNotification *)notification {
    // Get the user info dictionary that was received along with the notification.
    NSDictionary *userInfoDict = [notification userInfo];

    // Convert the received data into a NSString object.
    NSData *receivedData = [userInfoDict objectForKey:@"data"];
    NSString *message = [[NSString alloc] initWithData:receivedData encoding:NSUTF8StringEncoding];

    // Keep the sender's peerID and get its display name.
    MCPeerID *senderPeerID = [userInfoDict objectForKey:@"peerID"];
    NSString *senderDisplayName = senderPeerID.displayName;

    // Add this guess to the history text view.
    NSUInteger len = [[tvHistory text] length];
    NSString *history = [NSString stringWithFormat:@"%@ : %@\n\n", senderDisplayName, message];
    [self.tvHistory setText:[self.tvHistory.text stringByAppendingString:history]];
    [self.tvHistory scrollRangeToVisible:NSMakeRange([self.tvHistory.text length], len)];

}
-(BOOL)textFieldShouldReturn:(UITextField *)textField{
    [textField resignFirstResponder];
    return YES;
}

- (void)resetIdleTimer
{
    if (_idleTimer) {
        [_idleTimer invalidate];

    }

    // Schedule a timer to fire in kApplicationTimeoutInMinutes * 60
        int timeout = kSessionTimeoutInSeconds;
     _idleTimer = [NSTimer scheduledTimerWithTimeInterval:timeout
                                               target:self
                                        selector:@selector(idleTimerExceeded)
                                             userInfo:nil
                                              repeats:NO];
}

- (void)idleTimerExceeded {
    /* Post a notification so anyone who subscribes to it can be notified when
     * the application times out */
    [[NSNotificationCenter defaultCenter]
     postNotificationName:kSessionDidTimeoutNotification object:nil];
}
- (void) sessionDidTimeout:(NSNotification *) notif {

//    [self setUserInteraction:NO];
//    
//    [self.lblName setText:@"Session expired..."];
//    
//    NSLog(@"============================Session Expired...=====================");
//    
//    [[[self.appDelegate mpcHandler] session]  disconnect];
//    
//    if ([[[self appDelegate]mpcHandler] invited]) {
//        [self performSelector:@selector(advertisePeer) withObject:nil afterDelay:0.0];
//        [self performSelector:@selector(searchAndConnectPeer:) withObject:nil afterDelay:1.0];
//    }
}
zx81
  • 41,100
  • 9
  • 89
  • 105
Dattatray Deokar
  • 1,923
  • 2
  • 21
  • 31

1 Answers1

0

Check for BTM disconnection to service message in the logs .It is a problem with Apple Bluetooth which they have acknowledged.Try without Bluetooth i.e peer-peer wifi or infrastructure networks