Search code examples
iosapinetwork-programmingavaudioplayersoundcloud

How does Soundcloud app skip to next track so fast?


I'm building my first app and it's a Soundcloud client. Right now, everytime a track is selected to play, I have to go on and do a NSURLSessionDataTask fetch to get the binary data, but this takes a long time. And when I skip, to the next track, I have to add the logic in to download the next song ahead of time when the current song is playing... though, this is still slow if the user skips quickly:/

The Soundcloud native app skips instantly. How do it work? I've tried using Soundcloud iOS SDK but it is now deprecated.

Here is my song fetch:

-(void)fetchTrack: (SCTrack*)selectedTrack completionHandler: (void(^)(NSData *trackData, NSString *error)) completionHandler; {
NSString* clientID = @"41a5278fd8c704c3eb5a4a0ca38f9036";
NSString* streamURL = selectedTrack.stream_url;
NSString* urlString = [NSString stringWithFormat:@"%@?client_id=%@", streamURL, clientID];
NSURL* url = [[NSURL alloc]initWithString:urlString];

NSLog(@"%@", urlString);

NSMutableURLRequest* request = [[NSMutableURLRequest alloc]initWithURL:url];
request.HTTPMethod = @"GET";

NSURLSessionDataTask* dataTask = [[self session] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
    
    NSHTTPURLResponse* callResponse = (NSHTTPURLResponse*)response;
    if ([callResponse isKindOfClass:[NSHTTPURLResponse class]]) {
        
        NSInteger responseCode = [callResponse statusCode];
        if (responseCode >= 200 && responseCode <= 299) {
            
            NSData* trackData = data;
            
            NSLog(@"STREAM 200");
            [[NSOperationQueue mainQueue]addOperationWithBlock:^{
                NSLog(@"%@", data);
                completionHandler(trackData, nil);
            }];
        }else{
            NSLog(@"%ld", (long)responseCode);
        }
    }
}];

[dataTask resume];
}

This is how I'm playing and attempting to fetch the next song while the current track is playing:

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.selectedTrack = self.SCTrackList[indexPath.row];
self.selectedTrackRow = indexPath.row;

[[SoundCloudAPI sharedInstance]fetchTrack:self.selectedTrack completionHandler:^(NSData *trackData, NSString *error) {
    self.player = [[AVAudioPlayer alloc]initWithData: trackData error:nil];
    [self.player prepareToPlay];
    [self.player play];;
    
}];
[self prepareForNextTrack:self.selectedTrack];
}

-(void)prepareForNextTrack: (SCTrack*)trackPlaying  {
self.selectedTrackRow += 1;
self.selectedTrack = self.SCTrackList[self.selectedTrackRow];

[[SoundCloudAPI sharedInstance]fetchTrack:self.selectedTrack completionHandler:^(NSData *trackData, NSString *error) {
    self.trackDataToPlay = trackData;
}];
}


 - (IBAction)nextPressed:(id)sender {

self.player = [[AVAudioPlayer alloc]initWithData: self.trackDataToPlay error:nil];
[self.player prepareToPlay];
[self.player play];;

[self prepareForNextTrack:self.selectedTrack];
}

Also, I'm new, so I'm sure my code is pretty clunky and would appreciated if anyone can point out ways to improve.


Solution

  • So it turns I made things wayyyy more complicated than had to be. All I had to do was the dataWithContentsOfURL method to go retrieve the song passing in the token.

    NSData *data =[NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:@"%@?oauth_token=%@",self.selectedTrack.stream_url, self.token]]];
    

    And of course, put the data in the AVAudioPlayer.

    Basically, getting rid of my fetchTrack function above.