切换应用程序后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_data
和get_data_size
可以得到uint_8的数据和播放的大小
您将设置 NotificationCenter
以观察以下键
AVAudioSessionInterruptionNotification
和 AVAudioSessionRouteChangeNotification
[[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);
我用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_data
和get_data_size
可以得到uint_8的数据和播放的大小
您将设置 NotificationCenter
以观察以下键
AVAudioSessionInterruptionNotification
和 AVAudioSessionRouteChangeNotification
[[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);