2016-06-12 7 views
0

Я использую RemoteIO Audio Unit для воспроизведения звука в моем приложении с помощью kAudioUnitProperty_ScheduledFileIDs. Аудиофайлы находятся в формате Формат PCM. Как я могу реализовать функцию обратного вызова рендеринга для этого случая, чтобы я мог вручную изменять выборки буфера?
Вот мой код:
Ядро аудио: функция воспроизведения рендеринга воспроизведения изображения

static AudioComponentInstance audioUnit; 

AudioComponentDescription desc; 

desc.componentType = kAudioUnitType_Output; 
desc.componentSubType = kAudioUnitSubType_RemoteIO; 
desc.componentManufacturer = kAudioUnitManufacturer_Apple; 
desc.componentFlags = 0; 
desc.componentFlagsMask = 0; 

AudioComponent comp = AudioComponentFindNext(NULL, &desc); 

CheckError(AudioComponentInstanceNew(comp, &audioUnit), "error AudioComponentInstanceNew"); 


NSURL *playerFile = [[NSBundle mainBundle] URLForResource:@"short" withExtension:@"wav"]; 

AudioFileID audioFileID; 

CheckError(AudioFileOpenURL((__bridge CFURLRef)playerFile, kAudioFileReadPermission, 0, &audioFileID), "error AudioFileOpenURL"); 

// Determine file properties 
UInt64 packetCount; 
UInt32 size = sizeof(packetCount); 
CheckError(AudioFileGetProperty(audioFileID, kAudioFilePropertyAudioDataPacketCount, &size, &packetCount), 
       "AudioFileGetProperty(kAudioFilePropertyAudioDataPacketCount)"); 

AudioStreamBasicDescription dataFormat; 
size = sizeof(dataFormat); 
CheckError(AudioFileGetProperty(audioFileID, kAudioFilePropertyDataFormat, &size, &dataFormat), 
       "AudioFileGetProperty(kAudioFilePropertyDataFormat)"); 

// Assign the region to play 
ScheduledAudioFileRegion region; 
memset (&region.mTimeStamp, 0, sizeof(region.mTimeStamp)); 
region.mTimeStamp.mFlags = kAudioTimeStampSampleTimeValid; 
region.mTimeStamp.mSampleTime = 0; 
region.mCompletionProc = NULL; 
region.mCompletionProcUserData = NULL; 
region.mAudioFile = audioFileID; 
region.mLoopCount = 0; 
region.mStartFrame = 0; 
region.mFramesToPlay = (UInt32)packetCount * dataFormat.mFramesPerPacket; 
CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_ScheduledFileRegion, kAudioUnitScope_Global, 0, &region, sizeof(region)), 
       "AudioUnitSetProperty(kAudioUnitProperty_ScheduledFileRegion)"); 

// Prime the player by reading some frames from disk 
UInt32 defaultNumberOfFrames = 0; 
CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_ScheduledFilePrime, kAudioUnitScope_Global, 0, &defaultNumberOfFrames, sizeof(defaultNumberOfFrames)), 
       "AudioUnitSetProperty(kAudioUnitProperty_ScheduledFilePrime)"); 

AURenderCallbackStruct callbackStruct; 
callbackStruct.inputProc = MyCallback; 
callbackStruct.inputProcRefCon = (__bridge void * _Nullable)(self); 

CheckError(AudioUnitSetProperty(audioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &callbackStruct, sizeof(callbackStruct)), "error AudioUnitSetProperty[kAudioUnitProperty_setRenderCallback]"); 

CheckError(AudioUnitInitialize(audioUnit), "error AudioUnitInitialize"); 

Callback функция:

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

    printf("my callback"); 
    return noErr; 
} 

Audio Unit начала воспроизведения на кнопку печати:

- (IBAction)playSound:(id)sender { 

CheckError(AudioOutputUnitStart(audioUnit), "error AudioOutputUnitStart"); 

} 

Это код сбой при компиляции с kAudioUnitErr_InvalidProperty (-10879) ошибка. Цель состоит в том, чтобы изменить выборки буфера, которые были прочитаны с AudioFileID и отправить результат на колонки.

+0

Где находится 'MyCallback()'? – user3078414

+0

@ user3078414, добавленный в раздел 'UPD:' – jangofett

+0

'kAudioUnitErr_InvalidElement' aka' -10877' кажется ошибкой инициализации, _not_ ошибка времени выполнения, AFAIK. Я не понимаю, что вы имеете в виду, заявив, что «остальная часть кода работает нормально». Какова «структура» вашей программы? Вы говорите о «использовании AudioUnits». Это одна программа AU или вы используете _multiple AUs_? Зачем? Если да, подключаете ли вы их явно или используете API-интерфейс AUGraph? – user3078414

ответ

1

Увидев, как вы просто знакомы с основным звуком, я предлагаю вам сначала получить обратный звонок remoteIO, независимо от вашего файлового проигрывателя. Просто удалите весь код, связанный с файловым проигрывателем, и попробуйте сначала выполнить эту работу.

Затем, как только у вас будет это, перейдите к включению вашего файлового проигрывателя.

Насколько я понимаю, это неправильно, я думаю, вы вводите в заблуждение API аудиофайлов с аудиоустройством. Этот API используется для чтения файла в буфер, который вы вручную подаете на remoteIO, если вы хотите пройти этот маршрут, используйте Extended Audio File Services API, это намного проще. Предполагается, что свойство kAudioUnitProperty_ScheduledFileRegion вызывается на аудиоустройстве файлового проигрывателя. Чтобы получить один из них, вам нужно создать его так же, как ваш remmoteIO, за исключением того, что компонент ComponentSubType и компонентного типа AudioComponentDescription - это kAudioUnitSubType_AudioFilePlayer и kAudioUnitType_Generator соответственно. Затем, как только у вас будет это устройство, вам нужно будет подключить его к remoteIO, используя свойство kAudioUnitProperty_MakeConnection.

А если серьезно, начните с того, что вы получите обратный вызов remoteIO, а затем попробуйте сделать аудиоустройство файлового проигрывателя и подключить его (без обратного вызова), а затем оттуда.

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

+0

Большое спасибо за указание в правильном направлении. Не могли бы вы рассмотреть этот вопрос? http://stackoverflow.com/questions/37870051/ios-core-audio-audiofileplayer-unit-render-callback. Я подключил свой File Player и RemoteIO Units, и я слышу звук из динамиков, но снова застрял в функции Callback. Заранее спасибо. – jangofett