2010-04-02 18 views
4

我以編程方式生成音頻。我聽到我的緩衝區之間的沉默的差距。當我將手機掛在示波器上時,我發現每個緩衝區的前幾個樣本都丟失了,而且它們的位置是靜音。這種沉默的長度從幾乎沒有變化到20毫秒。AudioQueue吃了我的緩衝區(前15毫秒)

我的第一個想法是,我原來的回調函數需要太多的時間。我用盡可能最短的一個替換它 - 它一遍又一遍地重新排列相同的緩衝區。我觀察到同樣的行爲。

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); 
} 

回答

6

我不熟悉iPhone的音頻API,但它似乎是類似於其他的地方通常當系統處理完第一個緩衝區,你會排隊超過一個緩衝區,這樣一來,它可以立即開始處理下一個緩衝區(因爲它已經排隊),而第一個緩衝區的完成回調正在執行。

喜歡的東西:

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); 
} 
+0

感謝您指出我在初始化排隊超過一個緩衝區() - 這個重要的事實已經躲避我。實施這個建議以及回調的改變改善了我的情況,但是沒有解決它。我仍然錯過了一些緩衝區的前幾個ms。現在這種情況只發生在7個或8個數據包上,而我錯過了更少的樣本,但它仍然很明顯。 – iter 2010-04-02 06:15:14

+2

在這個簡單的例子中,它似乎並不重要,但以防萬一:有超過2個緩衝區有幫助(如果你還沒有嘗試過)?另外,你確定'buffer_data()是用一個完整的1/50秒的數據包填充一個緩衝區嗎? AUDIO_SAMPLES_PER_S的價值是什麼? – 2010-04-02 06:41:57

+0

感謝您的持續支持。如果我使用3個緩衝區而不是2個,我會停止丟失樣本。這看起來很神奇......我不舒服的那種魔法,因爲我無法解釋它。我想知道是否有某種雙緩衝正在進行。我之前曾嘗試使用我的緩衝區大小,使它們長達1秒('PPM_PACKETS_PER_SECOND = 1')。有2長緩衝區,我仍然失去樣本。使用3個短緩衝區,我可以找回所有放入的文件。 – iter 2010-04-02 07:27:17