gpt4 book ai didi

macos - CoreAudio AudioQueue 停止问题

转载 作者:行者123 更新时间:2023-12-02 04:58:05 26 4
gpt4 key购买 nike

我正在制作一个基于 CoreAudio 的 FLAC 播放器,遇到了一个与 AudioQueues 相关的棘手问题。我正在像这样初始化我的东西(以下划线开头的变量是实例变量):

    _flacDecoder = FLAC__stream_decoder_new();

AudioStreamBasicDescription asbd = {
.mFormatID = kAudioFormatLinearPCM,
.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked,
.mSampleRate = 44100,
.mChannelsPerFrame = 2,
.mBitsPerChannel = 16,
.mBytesPerPacket = 4,
.mFramesPerPacket = 1,
.mBytesPerFrame = 4,
.mReserved = 0
};

AudioQueueNewOutput(&asbd, HandleOutputBuffer, (__bridge void *)(self), CFRunLoopGetCurrent(), kCFRunLoopDefaultMode, 0, &_audioQueue);

for (int i = 0; i < kNumberBuffers; ++i) {
AudioQueueAllocateBuffer(_audioQueue, 0x10000, &_audioQueueBuffers[i]);
}

AudioQueueSetParameter(_audioQueue, kAudioQueueParam_Volume, 1.0);

44.1 kHz 的 16 位立体声 PCM,非常基本的设置。 kNumberBuffers 为 3,每个缓冲区为 0x10000 字节。我用这些回调填充缓冲区:

static void HandleOutputBuffer(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer){

FLACPlayer * self = (__bridge FLACPlayer*)inUserData;

UInt32 largestBlockSizeInBytes = self->_currentStreamInfo.max_blocksize * self->_currentStreamInfo.channels * self->_currentStreamInfo.bits_per_sample/8;

inBuffer->mAudioDataByteSize = 0;
self->_buffer = inBuffer;

while(inBuffer->mAudioDataByteSize <= inBuffer->mAudioDataBytesCapacity - largestBlockSizeInBytes){
FLAC__bool result = FLAC__stream_decoder_process_single(self->_flacDecoder);
assert(result);

if(FLAC__stream_decoder_get_state(self->_flacDecoder) == FLAC__STREAM_DECODER_END_OF_STREAM){
AudioQueueStop(self->_audioQueue, false);
break;
}
}

AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
}

static FLAC__StreamDecoderWriteStatus flacDecoderWriteCallback(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data){

FLACPlayer * self = (__bridge FLACPlayer *)client_data;

assert(frame->header.bits_per_sample == 16); // TODO

int16_t * bufferWritePosition = (int16_t*)((uint8_t*)self->_buffer->mAudioData + self->_buffer->mAudioDataByteSize);
for(int i = 0; i < frame->header.blocksize; i++){
for(int j = 0; j < frame->header.channels; j++){
*bufferWritePosition = (int16_t)buffer[j][i];
bufferWritePosition++;
}
}

int totalFramePayloadInBytes = frame->header.channels * frame->header.blocksize * frame->header.bits_per_sample/8;
self->_buffer->mAudioDataByteSize += totalFramePayloadInBytes;

return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}

static void flacDecoderMetadataCallback(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data){

FLACPlayer * self = (__bridge FLACPlayer*) client_data;

if(metadata->type == FLAC__METADATA_TYPE_STREAMINFO){
self->_currentStreamInfo = metadata->data.stream_info;
}
}

基本上,当队列请求新缓冲区时,我从 FLAC__stream_decoder 填充缓冲区,然后将其入队。就像其他人一样。当 libFLAC 告诉我已经到达文件末尾时,我告诉 AudioQueue 异步停止,直到它消耗完所有缓冲区的内容。但是,播放并没有播放到最后,而是提前停止了一点点。如果我删除这一行:

AudioQueueStop(self->_audioQueue, false);

一切正常;音频端到端播放,尽管我的队列一直运行到时间结束。如果我将该行更改为:

AudioQueueStop(self->_audioQueue, true);

然后播放立即/同步停止,正如您从 Apple 的文档中所期望的那样:

If you pass true, stopping occurs immediately (that is, synchronously). If you pass false, the function returns immediately, but the audio queue does not stop until its queued buffers are played or recorded (that is, the stop occurs asynchronously). Audio queue callbacks are invoked as necessary until the queue actually stops.

我的问题是:- 我做错了什么吗?- 我怎样才能播放我的音频直到结束,并适本地关闭队列?

最佳答案

当然,经过几个小时的努力,我在发布这个问题几分钟后找到了解决方案......问题是 AudioQueue 不关心在调用 AudioQueueStop(..., false) 之后 排队的缓冲区。所以现在我像这样喂队列,一切都像魅力一样:

static void HandleOutputBuffer(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer){

FLACPlayer * self = (__bridge FLACPlayer*)inUserData;

UInt32 largestBlockSizeInBytes = self->_currentStreamInfo.max_blocksize * self->_currentStreamInfo.channels * self->_currentStreamInfo.bits_per_sample/8;

inBuffer->mAudioDataByteSize = 0;
self->_buffer = inBuffer;

bool shouldStop = false;

while(inBuffer->mAudioDataByteSize <= inBuffer->mAudioDataBytesCapacity - largestBlockSizeInBytes){
FLAC__bool result = FLAC__stream_decoder_process_single(self->_flacDecoder);
assert(result);

if(FLAC__stream_decoder_get_state(self->_flacDecoder) == FLAC__STREAM_DECODER_END_OF_STREAM){
shouldStop = true;
break;
}
}

AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, NULL);
if(shouldStop){
AudioQueueStop(self->_audioQueue, false);
}
}

关于macos - CoreAudio AudioQueue 停止问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19624605/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com