StreamingKit icon indicating copy to clipboard operation
StreamingKit copied to clipboard

Player sometime never leaves STKAudioPlayerStateBuffering state

Open zsaraf opened this issue 5 years ago • 8 comments

I'm using this library to build a radio iOS app that has a directory of Icecast streams that the user can click on and listen to.

This library works very well 95% of the time, but 5% of the time, the player gets stuck in the STKAudioPlayerStateBuffering state and never changes, not reporting any errors at all. It seems like some kind of a race condition. Any idea why this could be happening?

- (BOOL)startAudioIO
{
    NSError *error = nil;
    
    AVAudioSessionCategory category = AVAudioSessionCategoryPlayAndRecord;
    AVAudioSessionCategoryOptions options = AVAudioSessionCategoryOptionAllowBluetooth | AVAudioSessionCategoryOptionDefaultToSpeaker;
    if ([AVAudioSession sharedInstance].category != category || [AVAudioSession sharedInstance].categoryOptions != options) {
        [[AVAudioSession sharedInstance] setCategory:category withOptions:options error:&error];
        if (error) {
            NSLog(@"STKAudioPlayer: Error setting category on audio session.");
            return NO;
        }
    }
    
    [[AVAudioSession sharedInstance] setActive:YES error:&error];
    if (error) {
        NSLog(@"STKAudioPlayer: Error starting audio session.");
        return NO;
    }
    
    return YES;
}

- (void)setupPlayer
{
    STKAudioPlayerOptions options;
    options.bufferSizeInSeconds = 2;

    _audioPlayer = [[STKAudioPlayer alloc] initWithOptions:options];
    _audioPlayer.delegate = self;
    
    [_audioPlayer appendFrameFilterWithName:@"FFT" block:^(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, void* frames)
     {
         uint16_t bytesPerSample = bytesPerFrame / channelsPerFrame;
         
         if (bytesPerSample == 2) {
             vDSP_vflt16((short *)frames, 1, self->_floatInputBuffer, 1, frameCount * channelsPerFrame);
         } else if (bytesPerSample == 4) {
             vDSP_vflt32((int *)frames, 1, self->_floatInputBuffer, 1, frameCount * channelsPerFrame);
         } else {
             NSLog(@"STKAudioPlayer: Other bytePerSample sizes are not supported. TODO(zsaraf): Test for this now!");
         }
         
         // 2^(n-1) because it is a signed number where n = 16 (short *)
         const float nBits = pow(2, (bytesPerSample * 8) - 1);
         vDSP_vsdiv(self->_floatInputBuffer, 1, &nBits, self->_floatNormalizedInputBuffer, 1, channelsPerFrame * frameCount);
         
         [[DFFTManager shared] processFFTWithInputBuffers:self->_fftArgBuffer inputChannels:channelsPerFrame numberOfSamples:frameCount interleaved:YES];
     }];
}

- (void)startStreamWithUrl:(NSString *)streamUrl
                streamName:(NSString *)streamName
               streamImage:(NSString *)streamImage
     streamCreatorUsername:(NSString *)streamCreatorUsername
{
    // Set values in case we get disconnected and need to reconnect.
    self->_streamUrl = streamUrl;
    self->_streamName = streamName;
    self->_streamImage = streamImage;
    self->_streamCreatorUsername = streamCreatorUsername;
    
    // Begin stream.
    dispatch_async(dispatch_get_main_queue(), ^{
        [self startAudioIO];
        
        if (self->_audioPlayer == nil) {
            [self setupPlayer];
        }
        
        [self->_audioPlayer play:streamUrl];
    });
}

- (void)stopStream
{
    dispatch_async(dispatch_get_main_queue(), ^{
        [self->_audioPlayer stop];
        
        [self cleanupStream];
   });
}

Any ideas at all on where to look?

Thanks Zach

zsaraf avatar May 06 '19 13:05 zsaraf

I've found that this error comes up because of issues with starting the AUGraph. AUGraphStart gets called and returns a successful status of 0. BUT the OutputRenderCallback is not being called.

Any ideas why this could be?

zsaraf avatar May 06 '19 14:05 zsaraf

Hi! Between finish and start stream put a mini delay for example in 0.1 - 0.2 seconds.

keba76 avatar May 07 '19 05:05 keba76

This hasn't helped at all unfortunately! The AUGraphStart call is not actually starting the graph/callback functions. Does anyone have any idea how to fix this?

zsaraf avatar May 07 '19 16:05 zsaraf

In your method - (void)setupPlayer, try setting bufferSizeInSeconds to 10 seconds instead of 2 seconds.

keba76 avatar May 07 '19 19:05 keba76

As one of the options for the occurrence of such a problem, there may be initialization of AudioSession and Remote Control. These actions must be performed before the player is first initialized and preferably as early as possible.

keba76 avatar May 15 '19 21:05 keba76

We are experience similar issues - it's for iOS 13 only and we are able to reproduce it when playing audios on 3G - buffering seems to be broken for both foreground and background playing. Sometimes StreamingKit goes into Buffering (reporting state change by delegate) and never recovers from that - it's also not reporting any errors for that case. Lot's of users reporting that problem lately - and we didn't change anything within our code around this - it has been just fine for a long long time.

grzegorzkrukowski avatar Nov 22 '19 17:11 grzegorzkrukowski

Is this issue relative to the #398 one?

iDevelopper avatar Nov 23 '19 07:11 iDevelopper

No - we are playing from valid URLa, but on crappy 3G connection buffering sometimes just does not resume playing and StreamingKit stucks after usually 2-3 minutes of playing - it goes to buffering and never recovers from there even by calling “play” again.

Sent from my iPhone

On 23 Nov 2019, at 08:06, Patrick [email protected] wrote:

 Is this issue relative to the #398 one?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or unsubscribe.

grzegorzkrukowski avatar Nov 23 '19 07:11 grzegorzkrukowski