GKVoiceChat not connecting nor sending voice data on GameCenter Match - iphone

I'm trying to set up voice-chat on a game I'm developing for iOS, it successfully creates the match, but when I try to set up the voice-chat it does nothing, what am I doing wrong? It runs without throwing errors. Here's the code I'm using to make the voice-chat.
- (void)establishVoice
{
if (![GKVoiceChat isVoIPAllowed])
return;
if (![self establishPlayAndRecordAudioSession])
return;
NSLog(#"Did stablish voice chat");
chat = [match voiceChatWithName:#"GeneralChat"];
[chat start]; // stop with [chat end];
chat.active = YES; // disable mic by setting to NO
chat.volume = 1.0f; // adjust as needed.
chat.playerStateUpdateHandler = ^(NSString *playerID, GKVoiceChatPlayerState state) {
switch (state)
{
case GKVoiceChatPlayerSpeaking:
// Highlight player's picture
NSLog(#"Speaking");
break;
case GKVoiceChatPlayerSilent:
// Dim player's picture
NSLog(#"Silent");
break;
case GKVoiceChatPlayerConnected:
// Show player name/picture
NSLog(#"Voice connected");
break;
case GKVoiceChatPlayerDisconnected:
// Hide player name/picture
NSLog(#"Voice disconnected");
break;
} };
}
Where establishPlayAndRecordAudioSession is:
- (BOOL) establishPlayAndRecordAudioSession
{
NSLog(#"Establishing Audio Session");
NSError *error;
AVAudioSession *audioSession = [AVAudioSession sharedInstance];
BOOL success = [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
if (!success)
{
NSLog(#"Error setting session category: %#", error.localizedFailureReason);
return NO;
}
else
{
success = [audioSession setActive: YES error: &error];
if (success)
{
NSLog(#"Audio session is active (play and record)");
return YES;
}
else
{
NSLog(#"Error activating audio session: %#", error.localizedFailureReason);
return NO;
}
}
return NO;
}
The code successfully logs "Did stablish voice chat", so it does run the code, but when I start talking, it doesn't seem to get the voice nor send it. What am I doing wrong? Am I missing something? P.S. I'm not getting the GKVoiceChatPlayerConnected fired.

Related

Facebook Dialog showing only in Portrait mode

I have a issue with the Login and sharing dialogs on my app. About a week ago they started appearing only on Portrait mode (either normal or upside down), but the landscape modes does not work.
NSArray *permissions = #[#"user_photos",
#"user_likes",
#"user_friends",
#"email"];
_loginManager = [[FBSDKLoginManager alloc] init];
_loginManager.loginBehavior = FBSDKLoginBehaviorWeb;
[_loginManager logInWithReadPermissions:permissions fromViewController:self handler:^(FBSDKLoginManagerLoginResult *result, NSError *error) {
if(result.isCancelled || error)
{
[self pressedCancel];
return;
}
NSSet* declinedPermissions = result.declinedPermissions;
for (NSString *declinedPermission in declinedPermissions) {
if(!nullOrEmpty(declinedPermission))
{
[self pressedCancel];
return;
}
}
if ([FBSDKAccessToken currentAccessToken]) {
// self.settings.facebookToken = [FBSDKAccessToken currentAccessToken].tokenString;
// Send data capture
if([EventData sharedInstance].dataCaptureSettings.enabled)
{
[FacebookHelper getUserInfoWithCompletion:
^(NSDictionary* userInfo, NSError* error)
{
if(!nullOrEmpty(userInfo))
{
[self captureData:userInfo];
} else {
[self captureData:nil];
}
[self didSignIn];
}];
return;
} else {
[self captureData:nil];
[self didSignIn];
}
}
}];
Here's a MPOC to replicate the issue:
https://www.dropbox.com/s/p62vajqfk916bz1/FBTest.zip?dl=0
Any ideas what may be causing this? Or how could I make it work on Landscape mode as well?
Thanks!
just in case anyone else has this issue, it was fixed on the newest Facebook SDK for iOS (4.38.1)

Facebook sdk 3.5 requests not working

In Facebook SDK 3.5, I'm trying to send an App Request using the following code
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:#"Join"
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
NSLog(#"request error");
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
NSLog(#"request FBWebDialogResultDialogNotCompleted");
}
else if([[resultURL description] hasPrefix:#"fbconnect://success?request="])
{
// Facebook returns FBWebDialogResultDialogCompleted even user
// presses "Cancel" button, so we differentiate it on the basis of
// url value, since it returns "Request" when we ACTUALLY
// completes Dialog
NSLog(#"request success");
}
else
{
// User Cancelled the dialog
NSLog(#"request cancelled");
}
}
}
];
if i use the above code with the Facebook sample FacebookAppID,URL types,FacebookDisplayName it's working fine.
But if i give my own acebookAppID,URL types,FacebookDisplayName the notifications were not delivered.
Any help appreciated....
I have configured "App on Facebook" and "Native iOS App" configurations in settings, Now the notifications are being delivered to iOS and Web App(facebook).
If the notifications are not being delivered to iOS Goto App--> Edit Settings--> App Details and change the category to games/business according to your need. Now the notifications will be delivered to your Desktop Facebook as well as iOS.
I have tried "Native Android App" configurations as well to deliver my notifications to desktop,iOS and android,but no luck as of now. I think there is a problem with android settings.please let me know if anyone have the answer.
Try this :-
1.>First setup your application on facebook by following Facebook url.
2.> Then use this code and modify according to your requirments.
-(void)inviteFriends
{
if ([[FBSession activeSession] isOpen])
{
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:#"put your message here"
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
[self requestFailedWithError:error];
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
[self requestFailedWithError:nil];
}
else if([[resultURL description] hasPrefix:#"fbconnect://success?request="])
{
// Facebook returns FBWebDialogResultDialogCompleted even user
// presses "Cancel" button, so we differentiate it on the basis of
// url value, since it returns "Request" when we ACTUALLY
// completes Dialog
[self requestSucceeded];
}
else
{
// User Cancelled the dialog
[self requestFailedWithError:nil];
}
}
}
];
}
else
{
/*
* open a new session with publish permission
*/
[FBSession openActiveSessionWithPublishPermissions:[NSArray arrayWithObject:#"publish_stream"]
defaultAudience:FBSessionDefaultAudienceFriends
allowLoginUI:YES
completionHandler:^(FBSession *session, FBSessionState status, NSError *error)
{
if (!error && status == FBSessionStateOpen)
{
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:nil];
[FBWebDialogs presentRequestsDialogModallyWithSession:nil
message:[self getInviteFriendMessage]
title:nil
parameters:params
handler:^(FBWebDialogResult result, NSURL *resultURL, NSError *error)
{
if (error)
{
[self requestFailedWithError:error];
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
[self requestFailedWithError:nil];
}
else if([[resultURL description] hasPrefix:#"fbconnect://success?request="])
{
// Facebook returns FBWebDialogResultDialogCompleted even user
// presses "Cancel" button, so we differentiate it on the basis of
// url value, since it returns "Request" when we ACTUALLY
// completes Dialog
[self requestSucceeded];
}
else
{
// User Cancelled the dialog
[self requestFailedWithError:nil];
}
}
}];
}
else
{
[self requestFailedWithError:error];
}
}];
}
}
Please check your app check permission. If permission not assign then please assign permissions whatever you want in your app
NSMutableDictionary* params = [NSMutableDictionary dictionaryWithObjectsAndKeys:/*assign permission here*/ nil];
here are the helper functions that calls delegates function OnFBSuccess and OnFBFailed.
- (void)requestSucceeded
{
NSLog(#"requestSucceeded");
id owner = [fbDelegate class];
SEL selector = NSSelectorFromString(#"OnFBSuccess");
NSMethodSignature *sig = [owner instanceMethodSignatureForSelector:selector];
_callback = [NSInvocation invocationWithMethodSignature:sig];
[_callback setTarget:owner];
[_callback setSelector:selector];
[_callback retain];
[_callback invokeWithTarget:fbDelegate];
}
- (void)requestFailedWithError:(NSError *)error
{
NSLog(#"requestFailed");
id owner = [fbDelegate class];
SEL selector = NSSelectorFromString(#"OnFBFailed:");
NSMethodSignature *sig = [owner instanceMethodSignatureForSelector:selector];
_callback = [NSInvocation invocationWithMethodSignature:sig];
[_callback setTarget:owner];
[_callback setSelector:selector];
[_callback setArgument:&error atIndex:2];
[_callback retain];
[_callback invokeWithTarget:fbDelegate];
}
So the class taht calls method InviteFriend MUST have these functions:
-(void)OnFBSuccess
{
CCLOG(#"successful");
// do stuff here
[login release];
}
-(void)OnFBFailed:(NSError *)error
{
if(error == nil)
CCLOG(#"user cancelled");
else
CCLOG(#"failed");
// do stuff here
// [login release];
}
- (void)requestFailedWithError:(NSError *)error
{
if(error == nil)
CCLOG(#"user cancelled");
else
CCLOG(#"failed");
}
i hope it helps you.

Handle ACAccountStoreDidChangeNotification for Facebook & Twitter in iOS 6+

I am using Social framework for Facebook & Twitter integration. For this I followed this link
Everything is working fine except when I app receives ACAccountStoreDidChangeNotification , it crashes.
App crashes when
1) I installed app for first time & user don't have Facebook / Twitter account configured in Settings.
2) When I call any method of Facebook / Twitter , it gives me error code 6 as I don't have account configured which is right.
3) I click on HOME button so my app enters background & add account in Settigs.
4) Once I configured account & come back to app , my app launches from background & receives ACAccountStoreDidChangeNotification.
5) In selector of ACAccountStoreDidChangeNotification my account object is nil so my app crashes. So I checked for the nil
Here is my code
#pragma mark - Request Facebook Account Access
-(void)requestFacebookAccountAccess
{
requestType = kNoOpRequest;
// Register for Account Change notification
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(accountChanged:) name:ACAccountStoreDidChangeNotification object:nil];
self.accountStore = [[ACAccountStore alloc]init];
ACAccountType *FBaccountType= [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
// Set facebook permissions
NSArray *permissions = nil;
// We need to ask for Basic permission first
if (![kUserDefaults boolForKey:FACEBOOK_BASIC_PERMISSION]) {
permissions = #[#"email",#"user_about_me",#"user_location",#"friends_about_me"];
self.isBasicFacebookPermissionsRequested = YES;
}
else {
permissions = #[#"email",#"user_about_me",#"user_location",#"friends_about_me",#"publish_stream"];
}
//use ACAccountStore to help create your dictionary
NSDictionary *dictFacebook = #{
ACFacebookAppIdKey: kFacebookAppIDKey,
ACFacebookPermissionsKey: permissions,
ACFacebookAudienceKey: ACFacebookAudienceFriends
};
[self.accountStore requestAccessToAccountsWithType:FBaccountType options:dictFacebook completion:^(BOOL granted, NSError *error) {
if (granted) {
if (self.isBasicFacebookPermissionsRequested) {
self.isBasicFacebookPermissionsRequested = NO;
[kUserDefaults saveBasicFacebookPermissionsGrantedStatus:YES];
//[self requestFacebookAccountAccess];
}
// User granted permission to Accout
NSArray *accountsArray = [self.accountStore accountsWithAccountType:FBaccountType];
if ([accountsArray count]>0) {
//It will always be the last object with SSO
self.facebookAccount = [accountsArray lastObject];
NSLog(#"In %s::IS MAIN THREAD:- %#",__PRETTY_FUNCTION__,[NSThread isMainThread]?#"YES":#"NO");
if ([self.delegate respondsToSelector:#selector(didFacebookAccountAccessGranted)]) {
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didFacebookAccountAccessGranted];
});
}
}
else {
[self showAlertWithTitle:#"Error" andMessage:#"You don't have any Facebook accounts set up yet.Please set a Facebbok account and try again."];
}
}
else {
DLog(#"User denied permission to Accout::Localized Error:- %#",error.localizedDescription);
if([error code]==6) {
[self showAlertWithTitle:#"Error" andMessage:#"Please setup facebook account from Settings"];
if ([self.delegate respondsToSelector:#selector(didFacebookAccountAccessDenied:)]) {
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didFacebookAccountAccessDenied:error];
});
}
}
else if ([self.delegate respondsToSelector:#selector(didFacebookAccountAccessDenied:)]) {
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didFacebookAccountAccessDenied:error];
});
}
else {
// User denied permission to Account
[self showAlertWithTitle:#"Error" andMessage:[NSString stringWithFormat:#"User denied permission to Accout::Error:- %#",error.localizedDescription]];
}
}
}];
}
#pragma mark - Get Logged In User Info
-(void)getLoggedInUserInfo
{
NSURL *requestURL = [NSURL URLWithString:#"https://graph.facebook.com/fql"];
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:#"SELECT current_location,uid,name,sex,birthday,email,pic FROM user WHERE uid=me()",#"q", nil];
requestType = kGetLoggedInUserInfoRequest;
[self requestDataUsingURL:requestURL parameters:dict requestMethod:SLRequestMethodGET];
}
#pragma mark - Request Data From Facebook
-(void)requestDataUsingURL:(NSURL*)requestURL parameters:(NSDictionary*)params requestMethod:(SLRequestMethod)reuqestMethod
{
SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeFacebook
requestMethod:reuqestMethod
URL:requestURL
parameters:params];
request.account = self.facebookAccount;
[request performRequestWithHandler:^(NSData *data,
NSHTTPURLResponse *response,
NSError *error)
{
NSDictionary *dictData =[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
if(!error)
{
if([dictData objectForKey:#"error"]!=nil)
{
DLog(#"Request Data From Facebook Errro:- %#",dictData);
[self attemptRenewCredentials];
if ([self.delegate respondsToSelector:#selector(didGetFacebookError:)]) {
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didGetFacebookError:dictData];
});
}
}
else {
// Process the response
//NSLog(#"Response Dictionary contains: %#", dictData );
if ([self.delegate respondsToSelector:#selector(didPostToFacebook:)]) {
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didPostToFacebook:dictData];
});
}
}
}
else{
if ([self.delegate respondsToSelector:#selector(didGetFacebookError:)]) {
dispatch_async(dispatch_get_main_queue(),^{
[self.delegate didGetFacebookError:dictData];
});
}
else {
[self showAlertWithTitle:#"Error" andMessage:#"Some error occured while processing Facebook request"];
}
}
}];
}
-(void)accountChanged:(NSNotification *)notif
{
if (self.facebookAccount!=nil) {
[self attemptRenewCredentials];
}
else {
[self requestFacebookAccountAccess];
}
}
#pragma mark - Attempt to Renew Credentials
-(void)attemptRenewCredentials
{
[self.accountStore renewCredentialsForAccount:(ACAccount *)self.facebookAccount completion:^(ACAccountCredentialRenewResult renewResult, NSError *error){
if(!error)
{
switch (renewResult) {
case ACAccountCredentialRenewResultRenewed:
NSLog(#"Good to go");
[self againRequestFacebook];
break;
case ACAccountCredentialRenewResultRejected:
NSLog(#"User declined permission");
break;
case ACAccountCredentialRenewResultFailed:
NSLog(#"non-user-initiated cancel, you may attempt to retry");
break;
default:
break;
}
}
else{
//handle error gracefully
NSLog(#"error from renew credentials%#",error);
}
}];
}
-(void)againRequestFacebook
{
switch (requestType) {
case kGetLoggedInUserInfoRequest:
[self getLoggedInUserInfo];
break;
case kGetFriendsInfoRequest:
[self getFacebookFriendsInfo];
break;
case kPostToWallRequest:
[self postToFacebookWallInBackgroundForUserId:fbUserIdForPost withParams:paramsToPost];
break;
default:
break;
}
}
#pragma mark - Remove Observer for Notification
-(void)dealloc
{
requestType = kNoOpRequest;
[[NSNotificationCenter defaultCenter] removeObserver:ACAccountStoreDidChangeNotification];
}
But accountChanged method gets called multiple times.
What is wrong in this ? How can I handle this situation ?
Any kind of help is highly appreciated.
Thanks in advance.
I am facing the same problem...so i used a work around by having a BOOL value in NSUserDefaults to execute accountChanged method only once
-(void)accountChanged:(NSNotification *)notif
{
BOOL calledAccountChanged =[[[NSUserDefaults standardUserDefaults] objectForKey:DidAccountChanged] boolValue];
if(!calledAccountChanged)
{
if (self.facebookAccount!=nil) {
[self attemptRenewCredentials];
}
else {
[self requestFacebookAccountAccess];
}
}
}
Then we can change DidAccountChanged value later in the code...
If you have better solution do post it...

iOS Gamecenter Programmatic Matchmaking

I'm trying to implement a real-time multiplayer game with a custom UI (no GKMatchMakerViewController). I'm using startBrowsingForNearbyPlayersWithReachableHandler:
^(NSString *playerID, BOOL reachable) to find a local player, and then initiating a match request with the GKMatchmaker singleton (which I have already initiated).
Here's where I'm having trouble. When I send a request, the completion handler fires almost immediately, without an error, and the match it returns has an expected player count of zero. Meanwhile, the other player definitely has not responded to the request.
Relevant code:
- (void) findMatch
{
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = NUM_PLAYERS_PER_MATCH; //2
request.maxPlayers = NUM_PLAYERS_PER_MATCH; //2
if (nil != self.playersToInvite)
{
// we always successfully get in this if-statement
request.playersToInvite = self.playersToInvite;
request.inviteeResponseHandler = ^(NSString *playerID, GKInviteeResponse
response)
{
[self.delegate updateUIForPlayer: playerID accepted: (response ==
GKInviteeResponseAccepted)];
};
}
request.inviteMessage = #"Let's Play!";
[self.matchmaker findMatchForRequest:request
withCompletionHandler:^(GKMatch *match, NSError *error) {
if (error) {
// Print the error
NSLog(#"%#", error.localizedDescription);
}
else if (match != nil)
{
self.currentMatch = match;
self.currentMatch.delegate = self;
// All players are connected
if (match.expectedPlayerCount == 0)
{
// start match
[self startMatch];
}
[self stopLookingForPlayers];
}
}];
}
Figured it out! I needed to call - (void)matchForInvite:(GKInvite *)invite completionHandler:(void (^)(GKMatch *match, NSError *error))completionHandler in my invitation handler so that both players have the same match data.

openAL streaming & interruptions

I made an iphone application which uses OpenAL to play many sounds.
These sounds are in mp3, quite heavy (more than 1mn)and I stream them (2 buffers per sound) in order to use less memory.
To manage interruptions, I use this code :
In OpenALSupport.c file :
//used to disable openAL during a call
void openALInterruptionListener ( void *inClientData, UInt32 inInterruptionState)
{
if (inInterruptionState == kAudioSessionBeginInterruption)
{
alcMakeContextCurrent (NULL);
}
}
//used to restore openAL after a call
void restoreOpenAL(void* a_context)
{
alcMakeContextCurrent(a_context);
}
In my SoundManager.m file :
- (void) restoreOpenAL
{
restoreOpenAL(mContext);
}
//OPENAL initialization
- (bool) initOpenAL
{
// Initialization
mDevice = alcOpenDevice(NULL);
if (mDevice) {
...
// use the device to make a context
mContext=alcCreateContext(mDevice,NULL);
// set my context to the currently active one
alcMakeContextCurrent(mContext);
AudioSessionInitialize (NULL, NULL, openALInterruptionListener, mContext);
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
NSError *setCategoryError = nil;
[[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategoryAmbient error: &setCategoryError];
...
}
And finally in my AppDelegate :
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[[CSoundManager getInstance] restoreOpenAL];
...
}
With this method the sounds are back after a call , but flows seem to be played randomly.
Is there a specific way to manage interruption with streaming sounds ? I don't find any article about that.
Thanks for your help.
Ok, I answer to my own question.
I solved the problem by managing error on my streaming method :
- (void) updateStream
{
ALint processed;
alGetSourcei(sourceID, AL_BUFFERS_PROCESSED, &processed);
while(processed--)
{
oldPosition = position;
NSUInteger buffer;
alSourceUnqueueBuffers(sourceID, 1, &buffer);
////////////////////
//code freshly added
ALint err = alGetError();
if (err != 0)
{
NSLog(#"Error Calling alSourceUnQueueBuffers: %d",err);
processed++;
//restore old position for the next buffer
position = oldPosition;
usleep(10000);
continue;
}
////////////////////
[self stream:buffer];
alSourceQueueBuffers(sourceID, 1, &buffer);
////////////////////
//code freshly added
err = alGetError();
if (err != 0)
{
NSLog(#"Error Calling alSourceQueueBuffers: %d",err);
processed++;
usleep(10000);
//restore old position for the next buffer
position = oldPosition;
}
///////////////////
}
}