切换应用程序后AudioQueue无法播放音频

AudioQueue cannot play audio after switch the application

我用Objective-c和C语言在iOS开发了一个音频播放应用程序,它可以在大多数情况下播放音频。但是当我将应用程序切换到后台然后再切换回来时,它不会播放音频。另一个问题是我用耳机打开时,如果我摘下耳机,它也会停止播放音频。

初始化函数为:

    - (instancetype)init {
    self = [super init];
    if (self) {
        sysnLock = [[NSLock alloc] init];

        if (_audioDescription.mSampleRate <= 0) {
            _audioDescription.mSampleRate = _sampleRates;
            _audioDescription.mFormatID = kAudioFormatLinearPCM;

            _audioDescription.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;

            _audioDescription.mChannelsPerFrame = _channels;

            _audioDescription.mFramesPerPacket = 1;

            _audioDescription.mBitsPerChannel = 16;
            _audioDescription.mBytesPerFrame = (_audioDescription.mBitsPerChannel / 8) * _audioDescription.mChannelsPerFrame;

            _audioDescription.mBytesPerPacket = _audioDescription.mBytesPerFrame * _audioDescription.mFramesPerPacket;
        }

        AudioQueueNewOutput(&_audioDescription, AudioPlayerCallback, (__bridge void *_Nullable)(self), nil, 0, 0,
                            &audioQueue);

        AudioQueueSetParameter(audioQueue, kAudioQueueParam_Volume, 100.0);

        for (int i = 0; i < QUEUE_BUFFER_SIZE; i++) {
            audioQueueBufferUsed[i] = false;

            osState = AudioQueueAllocateBuffer(audioQueue, MIN_SIZE_PER_FRAME, &audioQueueBuffers[i]);
        }

        osState = AudioQueueStart(audioQueue, NULL);
    }
    return self;
}

其中AudioPlayerCallback为重置audioBufferUsed的回调函数

音频播放函数为:

- (void)startPlay:(AudioData *)audioData {
    uint8_t *c_data = get_data(audioData);
    size_t c_data_size = get_data_size(audioData);

    [sysnLock lock];
    int i = 0;
    while (true) {
        if (!audioQueueBufferUsed[i]) {
            audioQueueBufferUsed[i] = true;
            break;
        } else {
            i++;
            if (i >= QUEUE_BUFFER_SIZE) {
                i = 0;
            }
        }
    }

    audioQueueBuffers[i]->mAudioDataByteSize = (unsigned int)c_data_size;
    memcpy(audioQueueBuffers[i]->mAudioData, c_data, c_data_size);
    AudioQueueEnqueueBuffer(audioQueue, audioQueueBuffers[i], 0, NULL);
    OSStatus status = AudioQueueStart(audioQueue, NULL);

    [sysnLock unlock];
}

其中get_dataget_data_size可以得到uint_8的数据和播放的大小

您将设置 NotificationCenter 以观察以下键 AVAudioSessionInterruptionNotificationAVAudioSessionRouteChangeNotification

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(interruption:) name:AVAudioSessionInterruptionNotification
  object:nil];

- (void)interruption:(NSNotification *)notiz {
    // handle stuff when audio interrupts
}

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(routeChanged:) name:AVAudioSessionRouteChangeNotification object:nil];

- (void)routeChanged:(NSNotification *)notiz {
    // handle stuff when route is changed, aka headphone jack in/out
}

在经典的编码风格中,您不要忘记在 dealloc 方法中删除观察者。

[[NSNotificationCenter defaultCenter] removeObserver:self name:... object:nil];

这将使您能够观察到令人不安的事件何时发生,并在需要时通过重新创建 AudioQueue、Start、Stop、Buffer 来采取相应的行动。

另一种方法是观察 AudioQueueBuffer API 属性的变化...

AudioQueueAddPropertyListener(AudioQueueRef inAQ, AudioQueuePropertyID inID, AudioQueuePropertyListenerProc inProc, void * inUserData);