2016-06-12 29 views
0

我正在使用RemoteIO音頻單元用於在我的應用中使用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"); 

回調函數:

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

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

按下按鈕音頻單元開始播放:

- (IBAction)playSound:(id)sender { 

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

} 

這代碼在編譯期間失敗kAudioUnitErr_InvalidProperty(-10879)錯誤。目標是修改已從AudioFileID中讀取的緩衝樣本,並將結果發送給發言人。

+0

'MyCallback()'在哪裏? – user3078414

+0

@ user3078414,添加到'UPD:' – jangofett

+0

部分'kAudioUnitErr_InvalidElement'又名'-10877'似乎是一個初始化錯誤,不是一個運行時錯誤AFAIK。我不明白你說的「其他代碼工作正常」是什麼意思。你的程序的「結構」是什麼?你說「使用AudioUnits」。這是一個單一的AU程序,還是使用_multiple AU?做什麼的?如果是這樣,你明確地連接它們還是使用'AUGraph' API? – user3078414

回答

1

鑑於您剛剛熟悉核心音頻,我建議您先讓remoteIO回調獨立於文件播放器工作。只要刪除所有與文件播放器相關的代碼,並嘗試首先使其工作。

然後,一旦你有這個工作,繼續合併你的文件播放器。

據我所知,這是錯誤的,我認爲你是音頻文件服務API與音頻單元混淆。這個API用於將文件讀入緩衝區,您可以手動將其提供給remoteIO,如果您想要使用此路由,請使用擴展音頻文件服務API,則它更容易。 kAudioUnitProperty_ScheduledFileRegion屬性應該在文件播放器音頻單元上調用。要獲得其中一個,您需要按照與remmoteIO相同的方式創建它,除了AudioComponentDescription的componentSubType和componentType分別爲kAudioUnitSubType_AudioFilePlayerkAudioUnitType_Generator。然後,一旦擁有該設備,您需要使用kAudioUnitProperty_MakeConnection屬性將其連接到remoteIO。

但嚴重的是,只需讓您的remoteIO回撥工作,然後嘗試製作文件播放器音頻單元並將其連接(無回叫),然後從那裏開始。

獨立地詢問關於這些步驟中的每一個的具體問題,發佈已嘗試過的代碼無法正常工作,您將得到很多幫助。

+0

非常感謝您指點正確的方向。你可以看看這個問題嗎? http://stackoverflow.com/questions/37870051/ios-core-audio-audiofileplayer-unit-render-callback。我連接了我的文件播放器和RemoteIO單元,我聽到揚聲器發出的聲音,但又回到了回撥功能。提前致謝。 – jangofett