I'm attempting to play the top tracks from the result of an SPArtistBrowse using cocoalibspotify. Most of the time this works flawlessly, but occasionally I get the following error:
Error Domain=com.spotify.CocoaLibSpotify.error Code=3 "The track cannot be played"
This happens only for specific tracks, and for affected tracks it is consistent and repeatable (e.g. the top track for Armin van Buren, spotify:track:6q0f0zpByDs4Zk0heXZ3cO, always gives this error when attempting to play using the code below). The odd thing is, if I use the simple player sample app and enter an affected track's URL, the track plays fine; so my hunch is it has something to do with the track being loaded from an SPArtistBrowse.
Here is the code I am using to play tracks:
- (void)playTrack
{
SPTrack *track = [self.artistBrowse.topTracks objectAtIndex:self.currentTrackIndex];
[SPAsyncLoading waitUntilLoaded:track then:^(NSArray *tracks) {
[self.playbackManager playTrack:track callback:^(NSError *error) {
if (error) {
self.currentTrackIndex++;
if (self.currentTrackIndex < self.artistBrowse.topTracks.count) {
[self playTrack];
} else {
[self.activityIndicator stopAnimating];
self.activityIndicator.alpha = 0;
self.nowPlayingLabel.text = #"Spotify Error";
}
} else {
[self.activityIndicator stopAnimating];
self.activityIndicator.alpha = 0;
self.nowPlayingLabel.text = track.name;
// Set "Now Playing" info on the iOS remote control
MPNowPlayingInfoCenter *infoCenter = [MPNowPlayingInfoCenter defaultCenter];
NSMutableDictionary *dic = [[NSMutableDictionary alloc] init];
[dic setValue:track.name forKey:MPMediaItemPropertyTitle];
[dic setValue:self.artistLabel.text forKey:MPMediaItemPropertyArtist];
infoCenter.nowPlayingInfo = dic;
}
}];
}];
}
The artist browse should affect anything - a track is a track. However, if you can reliably reproduce it, please fork CocoaLibSpotify and add a failing unit test to the unit test suite - that way we can fix it.
It's also possible that the Spotify playback service was unavailable right at the wrong time, but that's a fairly rare occurrence.
Related
I have a current speech recognition capture that works nicely - you say what you would like, and it get's it. Fairly accurate too for what it's worth...
The issue I'm having is such:
If I attempt to change languages after stopping and starting, it fails with the following errors
2018-05-23 00:51:51.878921-0400 APP[1237:332833] Speech error: The operation couldn’t be completed. (kAFAssistantErrorDomain error 209.)
2018-05-23 00:51:51.922965-0400 APP[1237:332833] Speech error: Corrupt
However, if I stop recording and reset with the original language, it will work just fine. For instance, even starting with Korean, any time I stop, switch to... Korean... then press start again, it works. No matter how many times I do this process.
The issue is, continuing my example, if I switch to a different language, EVEN English, after starting with Korean, it gives me that error (which is contained in my recognitionTaskWithRequest FYI).
It appears the starting language is irrelevant to whether it will
work, just as long as I choose a different language it fails, and when
I select the same starting language it works.
// Note: self.inputLanguageIdentifier is changed when you select a new language.
// I have tested to ensure this ID is correct each time.
// I.E. Korean prints ko-KR, English of course en-US, etc.
NSLocale *locale = [NSLocale alloc] initWithLocaleIdentifier:self.inputLanguageIdentifier]
speechRecognizer = [[SFSpeechRecognizer alloc] initWithLocale:locale];
speechRecognizer.delegate = self;
recognitionRequest = [[SFSpeechAudioBufferRecognitionRequest alloc] init];
AVAudioInputNode *inputNode = audioEngine.inputNode;
recognitionRequest.shouldReportPartialResults = YES;
recognitionTask = [speechRecognizer recognitionTaskWithRequest:recognitionRequest resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {
BOOL isFinal = NO;
if (result && !userDidTapCancel) {
// in the console.
NSLog(#"RESULT:%#", result.bestTranscription.formattedString);
[self updateTextForResult:result.bestTranscription.formattedString];
isFinal = !result.isFinal;
}
if (error) {
NSLog(#"Speech error: %#", error.localizedDescription);
[self stopListening];
}
}];
My stopListening is such:
- (void)stopListening {
isListening = NO;
[audioEngine stop];
[recognitionRequest endAudio];
[recognitionTask cancel];
}
UPDATE:
What I have found, is that upon resetting twice in a row (keeping the same newly selected language), the recording works as expected.
But as it stands I can't find a solution that allows it to work the first immediate time after changing languages... bizarre.
After seeing this question, I tried to code up a quick program that would save the watches accelerometer and gyroscope data to a file.
#implementation InterfaceController{
NSMutableArray *accData;
bool recording;
}
- (void)awakeWithContext:(id)context {
[super awakeWithContext:context];
// Configure interface objects here.
self.motionManager = [[CMMotionManager alloc] init];
[self.motionManager setAccelerometerUpdateInterval:.01];
}
- (IBAction)startStopRecording {
if (!recording){//We are starting to record.
recording = YES;
accData = [[NSMutableArray alloc] init];
[self.startRecording setTitle:#"Stop Recording"];
[self.motionManager startAccelerometerUpdatesToQueue:[NSOperationQueue currentQueue] withHandler:^(CMAccelerometerData *accelerometerData, NSError *error) {
[accData addObject:[NSString stringWithFormat:#"%f, %f, %f", accelerometerData.acceleration.x, accelerometerData.acceleration.y, accelerometerData.acceleration.z]];
}];
}else{
recording = NO;//we are stopping the recording
[self.motionManager stopAccelerometerUpdates];
[self.startRecording setTitle:#"Start Recording"];
[InterfaceController openParentApplication:#{ #"accData": accData } reply:^(NSDictionary *replyInfo, NSError *error) { //this method saves the array to a csv file.
NSLog(#"Data has been saved.");
}];
}
}
I had plotted this data and for the life of me, no matter how hard I shook the watch, all my plots looked like this:
Until 8 hours later, I started to suspect that I wasn't grabbing the acceleration data from the watch, but rather from the phone (sitting still on the table next to me). I ran some tests and confirmed that this is exactly what is happening.
Which leads me to the original question. How do I pull acceleration/gyro/data from the watch and not from the iPhone?
The problem was that I wasn't running watchOS2. I assumed I was but it's still in beta and I hadn't installed it. The data I was getting was accelerometer data from the phone. Also, currently, you can only get acc data from the watch using watchOS2 and not gyro data.
you can use CoreMotion framework to get activity data.
while I can only get accel data, the gyro often return false.
I am attempting to create a feature with my app that allows people to be easily added and/or removed from a group on iOS. The code below works perfectly if I:
1) add one person at a time
2) remove one person at a time
If however I select multiple people to add and/or remove simultaneously only the first action - first add if any or first remove if no additions - is committed to the address book. This method can be called over and over again with any one individual action and it will succeed. I cannot determine why I cannot get it to save multiple adds/deletes within the context of a single call to save. It should be pointed out that no error is giving and stepping through the code the booleans used to determine success indicate that everything worked perfectly.
I have attempted various combinations of adjusting code, for example: create a local address book, retrieve the groupRef, save the address book all within each of the for loops. I've also investigated reverting the address book after saving it to no avail. Thoughts or experiences?
-(IBAction)save:(id)sender
{
#synchronized(self)
{
CFErrorRef error = NULL;
BOOL success = NO;
BOOL successfulSave = NO;
ABAddressBookRef localAddressBook = ABAddressBookCreateWithOptions(NULL, &error);
group = ABAddressBookGetGroupWithRecordID(localAddressBook, groupID);
for (CFIndex addItemCount = 0; addItemCount < [theAddList count]; ++addItemCount)
{
NSNumber *addID = [theAddList objectAtIndex:addItemCount];
ABRecordRef thePersonID = ABAddressBookGetPersonWithRecordID(localAddressBook, [addID intValue]);
success = success || ABGroupAddMember(group, thePersonID, &error);
}
for (CFIndex removeItemCount = 0; removeItemCount < [theRemoveList count]; ++removeItemCount)
{
NSNumber *removeID = [theRemoveList objectAtIndex:removeItemCount];
ABRecordRef thePersonID = ABAddressBookGetPersonWithRecordID(localAddressBook, [removeID intValue]);
success = success || ABGroupRemoveMember(group, thePersonID, &error);
}
if (success)
{
successfulSave = ABAddressBookSave(localAddressBook, &error);
}
if (!(successfulSave && success))
{
UIAlertView *addressBookUpdateAlert = [[UIAlertView alloc] initWithTitle:#"AddressBook Error" message:#"An update to your address book could not be processed at this time. Try again shortly." delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
// we can't update a GUI element from a background thread - appears sensitivity didn't appear until iOS 8
[[NSOperationQueue mainQueue] addOperationWithBlock:
^{
[addressBookUpdateAlert show];
}];
}
else
{
[[self navigationController] popViewControllerAnimated:YES];
}
}
}
I can't explain it, but I made a minor change which should have done a better job of trapping an error and instead seems to caused to code to magically start working - which by the way is usually code for you over wrote memory somewhere.
Anyway I did the following and it started working:
Set success = YES before entering the loop
Changed the || test to an && test in both loops
All I changed and yet somehow it just started working...weird...I'm off to test/hammer the thing in case I'm seeing things...
I am developing a board game. Using Game Center for multiplayer, but currently stuck at how to send or receive invitations of GKTurnBasedMatch. I am creating match programmatically using:
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.defaultNumberOfPlayers = 2;
[GKTurnBasedMatch findMatchForRequest:request
withCompletionHandler:
^(GKTurnBasedMatch *match, NSError *error) {
if(error) {
NSLog(#"%#", error.localizedDescription);
return;
}
[self.delegate startGameForMatch:match];
}];
The GKTurnBasedMatch instance in parameter of above block, has only local player with other player as nil and I need to display details of opponent in the game.
NSMutableArray *participantIds = [[NSMutableArray alloc] init];
NSLog(#"%#", match.participants);
for (GKTurnBasedParticipant *participant in match.participants) {
if(participant.playerID) [participantIds addObject:participant.playerID];
}
[GKPlayer loadPlayersForIdentifiers:participantIds
withCompletionHandler:^(NSArray *players, NSError *error) {
NSMutableString *string = [[NSMutableString alloc] init];
for (GKPlayer *player in players) {
[string appendFormat:#"---- Alias: %# DisplayName: %#", player.alias, player.displayName];
}
NSLog(#"%#", string);
}];
Am I missing something or Game Center works like this?
I read that participants of the match wont get invitations until that GKTurnBasedParticipant is GKTurnBasedMatch.currentParticipant but I need to display the details of opponent when game started.
Thanks for the help. Point me in correct direction.
This happens when you create a match against a random opponent. Try creating a second test user in iTunesConnect and signing into that user on a second device.
Then, send that second test player an invite to be your friend. This will allow you to more easily test your game with multiplayer features without having to wait for a random match to be found.
After the friend request is accepted, try creating a new game once more. Now, invite your 'Friend' to your game and start your turn. You will now notice that the (null) variables will - for the most part - be filled in. Something like this should now appear in your log-
GKTurnBasedParticipant 0xb9432e0 - playerID:G:123456789 status:Invited matchOutcome:None lastTurnDate:(null) timeoutDate:(null)
Using the sandboxed Gamecenter.
No matter what I do the scores never appear in a leaderboard.
I am using the following code:
- (void)scoreReported: (NSError*) error {
NSLog(#"%#",[error localizedDescription]);
}
- (void)submitScore{
if(self.currentScore > 0)
{
NSLog(#"Score: %lli submitted to leaderboard %#", self.currentScore, self.currentLeaderBoard);
[gameCenterManager reportScore: self.currentScore forCategory: self.currentLeaderBoard];
}
}
And scoreReported doesnt produce an error, yet the score doesnt appear in the leaderboard. I know the category is correct as I use currentLeaderBoard in:
- (void)showLeaderboard {
NSLog(#"leaderboard = %#", self.currentLeaderBoard);
GKLeaderboardViewController *leaderboardController = [[GKLeaderboardViewController alloc] init];
if (leaderboardController != NULL)
{
leaderboardController.category = self.currentLeaderBoard;
//leaderboardController.category = nil;
leaderboardController.timeScope = GKLeaderboardTimeScopeWeek;
leaderboardController.leaderboardDelegate = self;
[self presentModalViewController: leaderboardController animated: YES];
}
}
I have tried the usual
2 different sandbox GC accounts to get the leaderboard working
Even tried 4 different GC accounts each logging in on both the simulator (iOS 6.1) and device (iOS 6.0.1)
Yet still no joy
any suggestions - or is it just that the sandboxed gamecenter is far too buggy!!! (I would raise a bug about sandbox but the apple bug reporting form has a bug in it so that doesnt work either)
Score reporting to Game Center works almost immediately for me, even in sandbox mode.
Here are the few things you can try
Make sure the the Leaderboard identifiers are correct when reporting scores (Should exactly match with "Leaderboard ID"s in iTunesConnect)
Try Deleting the test data under "Manage Game Center" section of iTunesConnect
Delete the application, launch "Game Center" application in your device and goto "Games" tab and remove your app. Reinstall the app and try reporting the score again.
Make sure [gkScore reportScoreWithCompletionHandler:^(NSError *error) doesn't return any error
For those who want to know this what I changed my submitScore method to:
- (void)submitScore {
GKScore * GCscore = [[GKScore alloc] initWithCategory:self.currentLeaderBoard];
GCscore.value = [[NSUserDefaults standardUserDefaults] integerForKey:#"NEWSCORE"];
[GCscore reportScoreWithCompletionHandler:^(NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^(void) {
if (error == NULL) {
NSLog(#"Score Sent");
} else {
NSLog(#"Score Failed, %#",[error localizedDescription]);
}
});
}];
}
and it worked