Перезапись AudioBufferList.mBuffers [0] .mData?

У меня есть аудиоустройство RemoteIO с обратным вызовом рендеринга. У меня уже есть буфер рендеринга аудио, и по соображениям производительности хотелось бы избежать memcpy,

OSStatus FMixerPlatformAudioUnit::AudioRenderCallback(void* RefCon, AudioUnitRenderActionFlags* ActionFlags,
const AudioTimeStamp* TimeStamp, UInt32 BusNumber,
UInt32 NumFrames, AudioBufferList* IOData)
{
IOData->mBuffers[0].mData = RenderedBufferPtr;
RefreshRenderedBufferPtr();
}

Это работает и звучит хорошо. Тем не менее, я беспокоюсь, что перезаписав IOData->mBuffers[0].mDataЯ мог бы оставить оригинальный буфер, который mData указывал на зависание, и, следовательно, может быть причиной утечки памяти. Это проблема переписать IOData->mBuffers[0].mData в процедуре InputCallback?

0

Решение

На любом текущем процессоре Apple arm64 время memcpy для каждого сэмпла примерно в 10 000 раз быстрее, чем период частоты сэмплирования, поэтому вряд ли это будет измеримый процент от частоты обратных вызовов аудиоустройства. Таким образом, замена буферов не будет работать заметно быстрее.

Но ваша большая проблема заключается в том, что NumFrames не гарантированно останутся неизменными при каждом последующем обратном вызове аудиоустройства в iOS, поэтому простое переключение указателя буфера — это не то же самое, что копирование точного запрошенного количества выборок или аудиокадров. Ваш звук будет зависать в зависимости от других событий на устройстве iOS (режимы энергосбережения, уведомления, телефонные звонки, нажатия клавиш и т. Д.)

Кроме того, если вы не выделяли его, вы не знаете размер выделения памяти для буфера IOData, который вы меняете, что может быть другим возможным источником повреждения памяти, если аудиоустройство принимает другой размер.

2

Другие решения

Я начну с раздражающего ответа, просто memcpy, Этот тип оптимизации будет невозможно измерить, я гарантирую это.

Теперь, чтобы ответить на ваш вопрос.

Без измерения трудно сказать, но если бы я выставил указатель на буферный список, как это сделали авторы фреймворка, я бы сохранил отдельный указатель на память, чтобы избежать именно такой ситуации.

Это, вероятно, не похоже на то, что они делают, но просто для иллюстрации того, как вы можете защитить свою инфраструктуру от этого типа уязвимости. internalRender проходит clientRender указатель на локальную переменную, которая создается в стеке при каждом рендеринге, поэтому вы можете манипулировать ею сколько угодно (пока вы не пытаетесь и не освободить ее), и вы не можете заставить ее потерять свой первоначальный указатель ( передан в качестве RefoCon для краткости).

//this is your callback
OSStatus clientRender(void* RefCon, AudioUnitRenderActionFlags* ActionFlags,
const AudioTimeStamp* TimeStamp, UInt32 BusNumber,
UInt32 NumFrames, AudioBufferList* IOData){

IOData->mBuffers[0].mData = nil;

return noErr;
}

//Framework calls this
OSStatus internalRender(void* RefCon, AudioUnitRenderActionFlags* ActionFlags,
const AudioTimeStamp* TimeStamp, UInt32 BusNumber,
UInt32 NumFrames, AudioBufferList* IOData){

void *internalMemory = RefCon;
AudioBufferList clientBufferlist;
clientBufferlist.mBuffers[0].mData = internalMemory;return clientRender(RefCon,ActionFlags,TimeStamp,BusNumber,NumFrames,&clientBufferlist);
}

Единственный способ сказать, это измерить. Откройте приложение Instruments и воспользуйтесь инструментом Leaks, и вы получите ответ. Но на самом деле, правильный способ сделать это просто memcpy, Это очень быстро, если вы не можете доказать обратное и является предполагаемым использованием.

1