Я знаю, что этот пост довольно длинный, но я стараюсь максимально контекстуализировать мою проблему, потому что считаю, что она довольно уникальна (не смог найти ни одной связанной проблемы, кроме этот. Последний вопрос находится в самом конце поста и вот полный код.
Прежде всего, немного контекста. я использую CoreAudio а также AudioToolbox библиотека, точнее Аудиоустройства. Я на MacOS. Моя конечная цель — записать звук с любого устройства ввода (следовательно, использовать аудиоустройства поверх простого AudioQueueBuffer) и записать его в аудиофайл. Я считаю, что самая сложная часть моей программы — конвертировать из LPCM в AAC (в моем случае) в течение один аудио блок, следовательно, AUGraph не используется.
Моя программа — это всего лишь одно аудиоустройство, заключенное в класс, AudioUnit mInputUnit
который является AUHAL единицей. Следовательно, я следовал этому это техническое примечание настроить это. По сути, я связываю область ввода элемента ввода (поскольку элемент вывода отключен) с аудиоустройством, т.е. моим встроенным микрофоном.
Затем я обновляю AudioFormat выходной области блока соответственно.
...
inputStream.mFormatID = kAudioFormatMPEG4AAC;
inputStream.mFormatFlags = 0;
inputStream.mBitsPerChannel = 0;
checkError(
AudioUnitSetProperty(
mInputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
1,
&inputStream,
propertySize
),
"Couldn't set output stream format.");
Следовательно, на данный момент, аудиоустройство должен работать следующим образом:
Запись с устройства ввода в LPCM [INPUT SCOPE] ==> Преобразование из LPCM в ==> Визуализация в AAC.
Обратите внимание, что каждый формат потока (вход и выход) использует 2 канала. Ни входной, ни выходной поток не имеет своего mFormatFlags
установлен в kAudioFormatIsNonInterleaved
так что они оба чередуются.
На самом деле, я думаю, что именно отсюда и возникает проблема, но не понимаю, почему.
На данный момент, кажется, все работает правильно. Проблема возникает, когда я пытаюсь визуализировать аудиоустройство после установки входного обратного вызова.
Я нашел записку, в которой говорится следующее:
«По соглашению, AUHAL устраняет перемежение многоканального звука. Это означает, что вы устанавливаете два AudioBuffer одного канала каждый вместо того, чтобы устанавливать один AudioBuffer с mNumberChannels == 2. Распространенной причиной проблем paramErr (-50) в вызовах AudioUnitRender () является наличие AudioBufferLists, чья топология (или расположение буферов) не совпадает с тем, что готово для создания устройства. Работая на уровне юнитов, вы почти всегда хотите делать это без чередования ».
Выдержка из: Крис Адамсон & Кевин Авила. «Learning Core Audio: практическое руководство по программированию звука для Mac и iOS». IBooks.
Следовательно, я следовал соответствующей структуре кода для воспроизведения аудио.
OSStatus Recorder::inputProc(
void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData
)
{
Recorder *This = (Recorder *) inRefCon;
CAStreamBasicDescription outputStream;
This->getStreamBasicDescription(kAudioUnitScope_Output, outputStream);
UInt32 bufferSizeBytes = inNumberFrames * sizeof(Float32);
UInt32 propertySize = offsetof(AudioBufferList, mBuffers[0]) + (sizeof(AudioBuffer) * outputStream.mChannelsPerFrame);
auto bufferList = (AudioBufferList*) malloc(propertySize);
bufferList->mNumberBuffers = outputStream.mChannelsPerFrame;
for(UInt32 i = 0; i < bufferList->mNumberBuffers; ++i)
{
bufferList->mBuffers[i].mNumberChannels = 1;
bufferList->mBuffers[i].mDataByteSize = bufferSizeBytes;
bufferList->mBuffers[i].mData = malloc(bufferSizeBytes);
}
checkError(
AudioUnitRender(
This->mInputUnit,
ioActionFlags,
inTimeStamp,
inBusNumber,
inNumberFrames,
bufferList
),
"Couldn't render audio unit.");
free(bufferList);
}
И затем, когда я пытаюсь сделать аудио, у меня появляется следующая ошибка Error: Couldn't render audio unit. (-50)
который на самом деле тот, который должен был фиксированный следуя примечанию, которое смущает меня еще больше.
На данный момент, я не знаю, связано ли это с моей общей архитектурой, т.е. AUGraph и добавить выходной модуль вместо попытки конвертировать из канонического формата в сжатый формат В рамках одного AUHAL модуля?
Или это как-то связано с тем, как я предварительно выделяю свой AudioBufferList?
Мне удалось решить эту проблему, переработав весь процесс. Короче говоря, у меня все еще есть уникальный модуль AUHAL, но вместо преобразования формата в модуле AUHAL я делаю это в обратном вызове рендеринга с расширенным аудиофайлом, который принимает исходный формат и формат назначения.
Вся задача состоит в том, чтобы найти правильное описание формата, которое в основном просто проверяет различные значения для mFormatID
, mFormatFlags
так далее…
Других решений пока нет …