关于 iphone:AudioQueue 吃了我的缓冲区(前 15 毫秒)

AudioQueue ate my buffer (first 15 milliseconds of it)

我正在以编程方式生成音频。我听到缓冲区之间的沉默间隙。当我将手机连接到示波器时,我发现每个缓冲区的前几个样本都丢失了,取而代之的是静默。这种静默的长度从几乎没有变化到长达 20 毫秒。

我的第一个想法是我原来的回调函数花费了太多时间。我用最短的可能替换它——它一遍又一遍地重新排列相同的缓冲区。我观察到同样的行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
AudioQueueRef aq;
AudioQueueBufferRef aq_buffer;
AudioStreamBasicDescription asbd;

void aq_callback (void *aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
    OSStatus s = AudioQueueEnqueueBuffer(aq, aq_buffer, 0, NULL);
}

void aq_init(void) {
    OSStatus s;

    asbd.mSampleRate = AUDIO_SAMPLES_PER_S;
    asbd.mFormatID = kAudioFormatLinearPCM;
    asbd.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    asbd.mBytesPerPacket = 1;
    asbd.mFramesPerPacket = 1;
    asbd.mBytesPerFrame = 1;
    asbd.mChannelsPerFrame = 1;
    asbd.mBitsPerChannel = 8;
    asbd.mReserved = 0;


    int PPM_PACKETS_PER_SECOND = 50;
    // one buffer is as long as one PPM frame
    int BUFFER_SIZE_BYTES = asbd.mSampleRate/PPM_PACKETS_PER_SECOND*asbd.mBytesPerFrame;

    s = AudioQueueNewOutput(&asbd, aq_callback, NULL, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &aq);
    s = AudioQueueAllocateBuffer(aq, BUFFER_SIZE_BYTES, &aq_buffer);

    // put samples in the buffer
    buffer_data(my_data, aq_buffer);

    s = AudioQueueStart(aq, NULL);
    s = AudioQueueEnqueueBuffer(aq, aq_buffer, 0, NULL);
}

我不熟悉 iPhone 音频 API,但它似乎与其他通常您会排队多个缓冲区的 API 相似,这样当系统完成处理第一个缓冲区时,它可以立即启动在执行第一个缓冲区的完成回调时处理下一个缓冲区(因为它已经排队)。

类似:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
AudioQueueRef aq;
AudioQueueBufferRef aq_buffer[2];
AudioStreamBasicDescription asbd;

void aq_callback (void *aqData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer) {
    // note that the callback tells us which buffer has been completed, so all
    //  we have to do is queue it back up
    OSStatus s = AudioQueueEnqueueBuffer(aq, inBuffer, 0, NULL);
}

void aq_init(void) {
    OSStatus s;

    asbd.mSampleRate = AUDIO_SAMPLES_PER_S;
    asbd.mFormatID = kAudioFormatLinearPCM;
    asbd.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    asbd.mBytesPerPacket = 1;
    asbd.mFramesPerPacket = 1;
    asbd.mBytesPerFrame = 1;
    asbd.mChannelsPerFrame = 1;
    asbd.mBitsPerChannel = 8;
    asbd.mReserved = 0;


    int PPM_PACKETS_PER_SECOND = 50;
    // one buffer is as long as one PPM frame
    int BUFFER_SIZE_BYTES = asbd.mSampleRate/PPM_PACKETS_PER_SECOND*asbd.mBytesPerFrame;

    s = AudioQueueNewOutput(&asbd, aq_callback, NULL, CFRunLoopGetCurrent(), kCFRunLoopCommonModes, 0, &aq);
    s = AudioQueueAllocateBuffer(aq, BUFFER_SIZE_BYTES, &aq_buffer[0]);
    s = AudioQueueAllocateBuffer(aq, BUFFER_SIZE_BYTES, &aq_buffer[1]);

    // put samples in the buffer - fill both buffers
    buffer_data(my_data, aq_buffer[0]);
    buffer_data(my_data, aq_buffer[1]);

    s = AudioQueueStart(aq, NULL);
    s = AudioQueueEnqueueBuffer(aq, aq_buffer[0], 0, NULL);
    s = AudioQueueEnqueueBuffer(aq, aq_buffer[1], 0, NULL);
}