Can't connect to [QBChat Instance] connect with User, in Quickblox - chat

I am using Quickblox Api, for chat and video chat. iOS. And I am using the latest version of the API
When I try to Make a video call,
most of the times i don't get video, only audio.
i get video on both ends 1 out of 15 times.
3 out of 10 times video on one end.
very weird. I have good internet connection. connecting to chat users are receiving the call. Can seem to find out the issue.

After spending sometime to find the issue, I received and help from Quickblox Help Center.
If your face such Behavior on the API
1.Make Sure that you set Delegate Methods in viewDidLod, not view did appear or etc. For Ex:
- (void)viewDidLoad {
[super viewDidLoad];
[[QBChat instance] addDelegate:self];
[QBRTCClient.instance addDelegate:self];
[QBSettings setCarbonsEnabled:YES];
}
Use Breakpoints to find out if they are getting called, once you make or receive calls.
2.Make Sure that your Calling methods are correct. An array containing Users must not equal to currentUser.ID.
NSInteger currentUserID = [QBSession currentSession].currentUser.ID;
int count = 0;
NSNumber *currentUserIndex = nil;
for (NSNumber *opponentID in opponentsIDs) {
if ([opponentID integerValue] == currentUserID) {
currentUserIndex = #(count);
break;
}
count++;
}
if (currentUserIndex) [opponentsIDs removeObjectAtIndex:[currentUserIndex intValue]];
QBRTCSession *session = [QBRTCClient.instance createNewSessionWithOpponents:opponentsIDs
withConferenceType:QBRTCConferenceTypeVideo];
NSDictionary *userInfo = #{ #"key" : #"value" };
[session startCall:userInfo];
if (session) {
self.currentSession = session;
[self performSegueWithIdentifier:#"openDialogSeg" sender:self];
}
else {
[SVProgressHUD showErrorWithStatus:#"You should login to use chat API. Session hasn’t been created. Please try to relogin the chat."];
}
}
Check View Layout, size and width. make sure they are set correctly.

Related

Multipeer Connectivity - State Not Changing

I'm working on an app the uses the Multipeer Conectivity Framework. So far everything is going great, I've implemented programmatic browsing and invitations.
My issue is when the user accepts the invitation the Browser is not receiving the state change - thereby not creating the session.
This is the advertiser did receive invitation method i have created using an action sheet integrated with blocks.
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser
didReceiveInvitationFromPeer:(MCPeerID *)peerID
withContext:(NSData *)context
invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler
{
[UIActionSheet showInView:self.view
withTitle:[[NSString alloc]initWithFormat:#"%# would like to share %# information with you.",peerID.displayName, (NSString *)context]
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:#"Deny"
otherButtonTitles:#[#"Accept"]
tapBlock:^(UIActionSheet *actionSheet, NSInteger buttonIndex) {
NSLog(#"%i",buttonIndex==1?true:false);
MCSession *newSession=[[MCSession alloc]initWithPeer:[[MCPeerID alloc] initWithDisplayName:#"CRAP23456"]];
[newSession setDelegate: self];
NSLog(#"button index %i ",buttonIndex==1?true:false);
invitationHandler(buttonIndex==1?YES:NO,newSession);
}];
}
The above method is being called and the invitation handler is returning the correct value.
My implementation from the browser side is very simple - and this is the method that should be called when the user either accepts/declines the method. However, it's only being called when the user declines the invite:
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state
{
NSLog(#"%d",state);
NSLog(#"%ld",(long)MCSessionStateConnected);
}
Thanks in advance.
James.
I hope one of these will help:
Implement session:didReceiveCertificate:fromPeer:certificateHandler:
I read here that this is necessary.
Keep browsing and advertising between two peers a one-way deal; that is, don't accept invitations on both ends if both are browsing as well (at least don't accept an invitation and pass same session you're browsing with in invitationHandler()).
Wrap your code in the didChangeState in a block like this:
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"%d",state);
NSLog(#"%ld",(long)MCSessionStateConnected);
});
I ran into this issue too. My code on the browser side looked like this:
MCSession *session = [[MCSession alloc] initWithPeer:[self peerID]];
session.delegate = self;
[browser invitePeer:peerID toSession:session withContext:nil timeout:30.0f];
The issue with this is that the browser does not retain a reference to the session and so ARC comes around and cleans it up before the other end had the opportunity to accept.
Changing it to the following fixed the issue:
_session = [[MCSession alloc] initWithPeer:[self peerID]];
_session.delegate = self;
[browser invitePeer:peerID toSession:_session withContext:nil timeout:30.0f];
.. where _session is an ivar on my class.
HTH

CCMotionManager, accelerometerData, gyroData, magnetometerData return nil

I'm working from Apple's Event Handling Guide for iOS. I'm using the pull method described near startAccelerometerUpdates. The pull method is fine for my purposes since I only need to read from the sensor once.
I'm getting a nil from the calls to accelerometerData, gyroData and magnetometerData in the code below on an iPhone 4, iPad Mini, and iPad Retina. isAccelerometerAvailable,isGyroAvailable, andisMagnetometerAvailableeach returnYES`. Two questions:
How does one determine the result from startAccelerometerUpdates and startGyroUpdates? They are void functions, so can I assume it can never fail? (Otherwise, it would throw or return a BOOL).
How does one get the last error from the call to accelerometerData, gyroData and magnetometerData?
EDIT: I had to call [NSThread sleepForTimeInterval:0.150f] to get data out of the sensor. Anything less and the sensor does not produce valid data.
The sleep adds a third question: how long does one need to pause to ensure the data arrives when the hardware is present?
Thanks in advance.
static CryptoPP::RandomPool pool;
static dispatch_once_t once = 0;
dispatch_once(&once, ^{
CryptoPP::SecByteBlock seed(32);
CryptoPP::OS_GenerateRandomBlock(true, seed.data(), seed.size());
pool.IncorporateEntropy(seed.data(), seed.size());
});
// First, send in all the uninitialized data. Then:
// sesnors[0,1,2] use accelerometer, if available
// sesnors[3,4,5] use gyroscope, if available
// sesnors[6,7,8] use magnetometer, if available
CryptoPP::SecBlock<double> sensors(3 * 3);
pool.IncorporateEntropy(sensors.BytePtr(), sensors.SizeInBytes());
CMMotionManager* mgr = [[CMMotionManager alloc] init];
if(mgr) {
[mgr startAccelerometerUpdates];
[mgr startGyroUpdates];
[mgr startMagnetometerUpdates];
[NSThread sleepForTimeInterval:0.150f];
if([mgr isAccelerometerAvailable]) {
CMAccelerometerData* accelData = [mgr accelerometerData];
if(accelData) {
sensors[0] = [accelData acceleration].x;
sensors[1] = [accelData acceleration].y;
sensors[2] = [accelData acceleration].z;
}
}
if([mgr isGyroAvailable]) {
CMGyroData* gyroData = [mgr gyroData];
if(gyroData) {
sensors[3] = [gyroData rotationRate].x;
sensors[4] = [gyroData rotationRate].y;
sensors[5] = [gyroData rotationRate].z;
}
}
if([mgr isMagnetometerAvailable]) {
CMMagnetometerData* magnetData = [mgr magnetometerData];
if(magnetData) {
sensors[6] = [magnetData magneticField].x;
sensors[7] = [magnetData magneticField].y;
sensors[8] = [magnetData magneticField].z;
}
}
pool.IncorporateEntropy(sensors.BytePtr(), sensors.SizeInBytes());
[mgr stopMagnetometerUpdates];
[mgr stopGyroUpdates];
[mgr stopAccelerometerUpdates];
[mgr release], mgr = nil;
}
When you do this:
mgr startAccelerometerUpdates];
[mgr setAccelerometerUpdateInterval:0.01f];
That means you will not start receiving information until 0.01 seconds later, and even then you'll only receive updates if the main thread is idle.
You are not waiting 0.01 seconds before checking for data, you're actually waiting about 0.00000000001 seconds. And I'm not sure, but I think your main thread might need to be idle even if you do wait longer.
I think you should go back to the documentation and have a look how you're supposed to read information from the sensors.
I recommend using blocks to process the motion data:
[mManager startAccelerometerUpdatesToQueue:[NSOperationQueue mainQueue] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
// process data
}];
You could tell the accelerometer to stop immediately after receiving the first value, if you only want it once.

CocoaLibSpotify Create playlists ending

I'm creating an IOS App based on cocoaLibSpotify.
In some point, I'm creating a Spotify playlist from an array of songs. I have previously obtained all the Spotify URIs and then I create the playlist and add all the tracks one by one.
The code below is in the logic class of the app and then I have a controller to show the results.
The problem is that I call this logic from the controller but I dont know the way to get back when the adding process has finished. I have tried to implement a delegate but im not sure how to do it...
Which is the right way to add tracks to a playlist? I have been searching on the documentation and in the GitHub repository but I have only found an example with two nested track addings... :S
Thanks in advance! (and sorry for my english)
- (void) createPlaylist:(NSArray*)spotifyURIs withName:(NSString*)name {
int songsRead = 0;
[container createPlaylistWithName:name callback:^(SPPlaylist *createdPlaylist) {
[SPAsyncLoading waitUntilLoaded:createdPlaylist timeout:kSPAsyncLoadingDefaultTimeout then:^(NSArray *loadedPlaylist, NSArray *notLoadedPlaylist) {
for (int i=[spotifyURIs count]-1; i>=0; i--) {
NSString *trackURI = spotifyURIs[i];
if (trackURI != nil){
[[SPSession sharedSession] trackForURL:[NSURL URLWithString:trackURI] callback:^(SPTrack *track) {
if (track != nil) {
[createdPlaylist addItems:[NSArray arrayWithObject: track] atIndex:[[createdPlaylist items] count] callback:nil];
}
}];
}
songsRead++;
// If I have read the whole tracklist, end of the process, returning to controller...
if (songsRead == [spotifyURIs count]){
// ...
}
}
}];
}];
}
What you need is to use the KVO system on your new playlist or using BLOCKS
you can implement something like this
typedef void (^spotifycompletionWithData)(id data);
-(void)addTrack:(NSString *)trackURI withCompletionBlock:(spotifycompletionWithData)CompletionBlock;
then whenever you call the function you should return the loaded SPTRACK within the completion block i hope its helping

Game Center- handling failed achievement submissions?

Im a noob in game center # games generally. Im making my second game now and implemented the game center.
If the internet is available, there is no problem, everything works well.
But just now I purposely make the internet unreachable, and when I get an achievement, obviously it does not register to the Game Center's Achievement.
How and what's the best way to handle this issue?
Thank you....
You could add the GKAchievement objects that fail to register to an array and then resend them when you get back connectivity. You should also consider committing that array to persistent storage, in case your app terminates before it has a chance to send those achievements. Try this in your completion handler:
// Load or create array of leftover achievements
if (achievementsToReport == nil) {
achievementsToReport = [[NSKeyedUnarchiver unarchiveObjectWithFile:pathForFile(kAchievementsToReportFilename)] retain];
if (achievementsToReport == nil) {
achievementsToReport = [[NSMutableArray array] retain];
}
}
#synchronized(achievementsToReport) {
if(error == nil)
{
// Achievement reporting succeded
// Resend any leftover achievements
BOOL leftoverAchievementReported = NO;
while ([achievementsToReport count] != 0) {
[self resendAchievement:[achievementsToReport lastObject]];
[achievementsToReport removeLastObject];
leftoverAchievementReported = YES;
}
// Commit leftover achievements to persistent storage
if (leftoverAchievementReported == YES) {
[NSKeyedArchiver archiveRootObject:achievementsToReport toFile:pathForFile(kAchievementsToReportFilename)];
}
}
else
{
// Achievement reporting failed
[achievementsToReport addObject:theAchievement];
[NSKeyedArchiver archiveRootObject:achievementsToReport toFile:pathForFile(kAchievementsToReportFilename)];
}
}
Hope this helps.
I see that the two answers here focus on the specific mechanisms for archiving the undelivered achievement messages. For a higher-level description of the overall approach, you can see my answer to this related question: Robust Game Center Achievement code
Achievements (and all of the gamecenter stuff like leaderboard updates) conform to NSCoding. You can store them if you get an error submitting them and submit them later. This is what apple recommends in their docs.
Your application must handle errors when it fails to report progress to Game Center. For example, the device may not have had a network when you attempted to report the progress. The proper way for your application to handle network errors is to retain the achievement object (possibly adding it to an array). Then, your application needs to periodically attempt to report the progress until it is successfully reported. The GKAchievement class supports the NSCoding protocol to allow your application to archive an achievement object when it moves into the background.
from: http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/GameKit_Guide/Achievements/Achievements.html#//apple_ref/doc/uid/TP40008304-CH7-SW13
// Submit an achievement to the server and store if submission fails
- (void)submitAchievement:(GKAchievement *)achievement
{
if (achievement)
{
// Submit the achievement.
[achievement reportAchievementWithCompletionHandler: ^(NSError *error)
{
if (error)
{
// Store achievement to be submitted at a later time.
[self storeAchievement:achievement];
}
else
{
NSLog(#"Achievement %# Submitted..",achievement);
if ([storedAchievements objectForKey:achievement.identifier]) {
// Achievement is reported, remove from store.
[storedAchievements removeObjectForKey:achievement.identifier];
}
[self resubmitStoredAchievements];
}
}];
}
}
In case anyone stumbles upon this question in the future, Apple now has sample code for submitting achievements that includes a way to archive achievements that failed to submit (due to no network connection, etc). You'll find it in the Game Center programming guide.

Game Center iPhone - Load Achievement Progress

I have my app give a notification when a Game Center achievement is achieved/reaches 100%, however it shows the notification every times the user completes it, but I only want it to notify the first time in actually completed.
I found this in the Apple docs:
http://developer.apple.com/library/ios/documentation/NetworkingInternet/Conceptual/GameKit_Guide/Achievements/Achievements.html#//apple_ref/doc/uid/TP40008304-CH7-SW11
However didn't quite understand how it help fix my issue.
I only want to call this notification once, when the achievement is first achieved. So only show it if its not already achieved.
Edit
I have this to unlock the achievement:
- (void) reportAchievementIdentifier: (NSString*) identifier percentComplete: (float) percent
{
GKAchievement *achievement = [[[GKAchievement alloc] initWithIdentifier: identifier] autorelease];
if (achievement)
{
achievement.percentComplete = percent;
[achievement reportAchievementWithCompletionHandler:^(NSError *error)
{
if (error != nil)
{
// Retain the achievement object and try again later (not shown).
}
}];
}
}
And unlock with this:
[self reportAchievementIdentifier:identifier percentComplete:percent];
Then show the notification with this line:
[[GKAchievementHandler defaultHandler] notifyAchievementTitle:#"Title" andMessage:#"Message"];
So do I simply need something like this in that code chunk?
if (achievement.completed != TRUE) {
[[GKAchievementHandler defaultHandler] notifyAchievementTitle:#"Title" andMessage:#"Message"];
}
There's a "completed"-property in GKAchievement... Try to make a new GKAchievement and check if it's not completed, then unlock it.