Шум AudioUnit, если нет выходного буфера

Я пытаюсь реализовать воспроизведение звука PCM, полученного с удаленного сервера через сокет. Вот мой предыдущий вопрос ссылка. Это отлично работает, так как я использую круговой буфер, чтобы всегда подавать входящий буфер.

Однако у меня есть проблема, связанная с тем, что создается огромный шумовой звук, если у меня нет буфера, подаваемого на мой выход. Это происходит, когда я начинаю использовать AudioOutputUnitStart(_audioUnit) и когда нет буфера для воспроизведения.

Я подозреваю, что мне нужно исправить это в моей функции OutputRenderCallback ниже, или, может быть, мне нужно сделать что-то еще:

static OSStatus OutputRenderCallback(void                        *inRefCon,
                                     AudioUnitRenderActionFlags  *ioActionFlags,
                                     const AudioTimeStamp        *inTimeStamp,
                                     UInt32                      inBusNumber,
                                     UInt32                      inNumberFrames,
                                     AudioBufferList             *ioData){


    Test *output = (__bridge Test*)inRefCon;


    TPCircularBuffer *circularBuffer = [output outputShouldUseCircularBuffer];
    if( !circularBuffer ){
        SInt32 *left  = (SInt32*)ioData->mBuffers[0].mData;
        for(int i = 0; i < inNumberFrames; i++ ){
            left[  i ] = 0.0f;
        }
        return noErr;
    };

    int32_t bytesToCopy = ioData->mBuffers[0].mDataByteSize;
    SInt16* outputBuffer = ioData->mBuffers[0].mData;

    uint32_t availableBytes;
    SInt16 *sourceBuffer = TPCircularBufferTail(circularBuffer, &availableBytes);

    int32_t amount = MIN(bytesToCopy,availableBytes);
    memcpy(outputBuffer, sourceBuffer, amount);

    TPCircularBufferConsume(circularBuffer,amount);

    return noErr;
}

Я очень ценю вашу помощь. Спасибо.


person akaiz    schedule 03.05.2018    source источник


Ответы (2)


Обратный вызов аудиоустройства требует, чтобы вы всегда помещали запрошенное количество выборок в буферы AudioBufferList. Ваш код не делает этого, если сумма (из этого доступного циклического буфера) меньше.

Поэтому всегда помещайте что-то в буфер вывода, как это делает ваш код, если нет кругового буфера.

Кстати: вызов метода:

[output outputShouldUseCircularBuffer]

внутри обратного вызова является нарушением правил Apple для звука в реальном времени.

person hotpaw2    schedule 04.05.2018
comment
Спасибо @hotpaw2. Ваш комментарий помог мне исправить шум. Извините, я также не понял, что я могу сделать с вызовом метода, который вы предложили, который нарушает правила Apple для звука в реальном времени. Как вы можете видеть в моем коде, я использую его для доступа к своему кольцевому буферу. - person akaiz; 04.05.2018

Я отправляю свой ответ на случай, если кто-то еще споткнется в том же месте, что и я. Я новичок в задаче c, поэтому, если у кого-то есть лучшее решение. Я приветствую любые предложения.

Как предположил @hotpaw2, AudioBufferList нужно наполнять сэмплами, и в моем случае, когда в моем циркулярном буфере ничего не было. Мне пришлось передать AudioBufferList с кадрами, установленными на 0.0f

static OSStatus OutputRenderCallback(void                        *inRefCon,
                                 AudioUnitRenderActionFlags  *ioActionFlags,
                                 const AudioTimeStamp        *inTimeStamp,
                                 UInt32                      inBusNumber,
                                 UInt32                      inNumberFrames,
                                 AudioBufferList             *ioData){

Test *output = (__bridge Test*)inRefCon;

TPCircularBuffer *circularBuffer = [output outputShouldUseCircularBuffer];

int32_t bytesToCopy = ioData->mBuffers[0].mDataByteSize;
SInt16* outputBuffer = ioData->mBuffers[0].mData;

uint32_t availableBytes;
SInt16 *sourceBuffer = TPCircularBufferTail(circularBuffer, &availableBytes);

int32_t amount = MIN(bytesToCopy,availableBytes);

if (amount>0) {
        memcpy(outputBuffer, sourceBuffer, amount);
        TPCircularBufferConsume(circularBuffer,amount);
}
else{

    SInt32 *left  = (SInt32*)ioData->mBuffers[0].mData;
    for(int i = 0; i < inNumberFrames; i++ ){
        left[  i ] = 0.0f;
    }
    return noErr;

}

return noErr; }
person akaiz    schedule 04.05.2018