从iOS上的“audio单元渲染过程”触发UI代码

我有一个多通道混音器audio单元在iOS应用程序中播放audio文件,我需要弄清楚如何更新应用程序的用户界面,并执行重置,当callback命中最长的audio文件的结尾(设置为在公共汽车0上运行)。 由于我的代码如下所示,我正在尝试使用KVO来实现此目的(使用布尔variablestapesUnderwaytapesUnderway是必要的,因为此Objective-C代码在其正常域之外运行,请参阅http://www.cocoabuilder.com/ archive / cocoa / 57412-nscfnumber-no-pool-in-place-just-leaking.html )。

 static OSStatus tapesRenderInput(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) { SoundBufferPtr sndbuf = (SoundBufferPtr)inRefCon; UInt32 bufferFrames = sndbuf[inBusNumber].numFrames; AudioUnitSampleType *in = sndbuf[inBusNumber].data; // These mBuffers are the output buffers and are empty; these two lines are just setting the references to them (via outA and outB) AudioUnitSampleType *outA = (AudioUnitSampleType *)ioData->mBuffers[0].mData; AudioUnitSampleType *outB = (AudioUnitSampleType *)ioData->mBuffers[1].mData; UInt32 sample = sndbuf[inBusNumber].sampleNum; // -------------------------------------------------------------- // Set the start time here if(inBusNumber == 0 && !tapesFirstRenderPast) { printf("Tapes first render past\n"); tapesStartSample = inTimeStamp->mSampleTime; tapesFirstRenderPast = YES; // MAKE SURE TO RESET THIS ON SONG RESTART firstPauseSample = tapesStartSample; } // -------------------------------------------------------------- // Now process the samples for(UInt32 i = 0; i < inNumberFrames; ++i) { if(inBusNumber == 0) { // ------------------------------------------------------ // Bus 0 is the backing track, and is always playing back outA[i] = in[sample++]; outB[i] = in[sample++]; // For stereo set desc.SetAUCanonical to (2, true) and increment samples in both output calls lastSample = inTimeStamp->mSampleTime + (Float64)i; // Set the last played sample in order to compensate for pauses // ------------------------------------------------------ // Use this logic to mark end of tune if(sample >= (bufferFrames * 2) && !tapesEndPast) { // USE KVO TO NOTIFY METHOD OF VALUE CHANGE NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; FuturesEPMedia *futuresMedia = [FuturesEPMedia sharedFuturesEPMedia]; NSNumber *boolNo = [[NSNumber alloc] initWithBool: NO]; [futuresMedia setValue: boolNo forKey: @"tapesUnderway"]; [boolNo release]; [pool release]; tapesEndPast = YES; } } else { // ------------------------------------------------------ // The other buses are the open sections, and are synched through the tapesSectionsTimes array Float64 sectionTime = tapesSectionTimes[inBusNumber] * kGraphSampleRate; // Section time in samples Float64 currentSample = inTimeStamp->mSampleTime + (Float64)i; if(!isPaused && !playFirstRenderPast) { pauseGap += currentSample - firstPauseSample; playFirstRenderPast = YES; pauseFirstRenderPast = NO; } if(currentSample > (tapesStartSample + sectionTime + pauseGap) && sample < (bufferFrames * 2)) { outA[i] = in[sample++]; outB[i] = in[sample++]; } else { outA[i] = 0; outB[i] = 0; } } } sndbuf[inBusNumber].sampleNum = sample; return noErr; } 

在这个variables被改变的时候,它触发了一个自我的方法,但是当从这个callback函数执行的时候会导致一个不可接受的延迟(20-30秒)(我想这是因为它是以高优先级运行的Objective-C代码audio线程?)。 如何有效地触发这样的改变,而不会拖延? (触发器会将暂停button更改为播放button,并调用重置方法为下一次播放做准备。)

谢谢

是。 由于其优先级高,因此不要在渲染线程中使用objc代码。 如果将状态存储在内存中(ptr或struct),然后在主线程中获取一个计时器来轮询(检查)内存中的值。 计时器不需要像渲染线程那么快,并且非常准确。

尝试这个。

全球:

 BOOL FlgTotalSampleTimeCollected = False; Float64 HigestSampleTime = 0 ; Float64 TotalSampleTime = 0; 

在 – (OSStatus)setUpAUFilePlayer:

 AudioStreamBasicDescription fileASBD; // get the audio data format from the file UInt32 propSize = sizeof(fileASBD); CheckError(AudioFileGetProperty(inputFile, kAudioFilePropertyDataFormat, &propSize, &fileASBD), "couldn't get file's data format"); UInt64 nPackets; UInt32 propsize = sizeof(nPackets); CheckError(AudioFileGetProperty(inputFile, kAudioFilePropertyAudioDataPacketCount, &propsize, &nPackets), "AudioFileGetProperty[kAudioFilePropertyAudioDataPacketCount] failed"); Float64 sTime = nPackets * fileASBD.mFramesPerPacket; if (HigestSampleTime < sTime) { HigestSampleTime = sTime; } 

在RenderCallBack中:

 if (*actionFlags & kAudioUnitRenderAction_PreRender) { if (!THIS->FlgTotalSampleTimeCollected) { [THIS setFlgTotalSampleTimeCollected:TRUE]; [THIS setTotalSampleTime:(inTimeStamp->mSampleTime + THIS->HigestSampleTime)]; } } else if (*actionFlags & kAudioUnitRenderAction_PostRender) { if (inTimeStamp->mSampleTime > THIS->TotalSampleTime) { NSLog(@"inTimeStamp->mSampleTime :%f",inTimeStamp->mSampleTime); NSLog(@"audio completed"); [THIS callAudioCompletedMethodHere]; } } 

这对我有效。 在设备中testing。