RemoteIO音频问题 - 模拟器=好 - 设备=坏

时间:2010-12-01 14:16:40

标签: iphone c core-audio audiounit

O.K,所以我使用核心音频从10个不同的样本源中提取音频,然后在我的回调函数中将它们混合在一起。

它在模拟器中运行完美,一切都很顺利。当我试图在4.2 iphone设备上运行时,我遇到了麻烦。

如果我在回调中混合2个音频文件,一切正常。 如果我混合使用5或6个音频文件,音频会播放但是在很短的时间后音频会降级,最终没有音频会进入扬声器。 (回调不会停止)。

如果我尝试混合10个音频文件,则回调会运行,但根本不会发出音频。

这几乎就像回调时间不多了,这可能解释了我混合5或6的情况,但不会解释混合10个音频源的最后一个案例,其中根本没有播放音频。

我不确定以下内容是否有任何影响,但在调试时此消息始终打印到控制台。这可以说明问题是什么吗?

mem 0x1000 0x3fffffff cache
mem 0x40000000 0xffffffff none
mem 0x00000000 0x0fff none
run
Running…
[Switching to thread 11523]
[Switching to thread 11523]
Re-enabling shared library breakpoint 1
continue
warning: Unable to read symbols for /Developer/Platforms/iPhoneOS.platform/DeviceSupport/4.2.1 (8C148)/Symbols/usr/lib/info/dns.so (file not found).

**设置我的回调**

#pragma mark -
#pragma mark Callback setup & control

- (void) setupCallback

{
    OSStatus status;


    // Describe audio component
    AudioComponentDescription desc;
    desc.componentType = kAudioUnitType_Output;
    desc.componentSubType = kAudioUnitSubType_RemoteIO;
    desc.componentFlags = 0;
    desc.componentFlagsMask = 0;
    desc.componentManufacturer = kAudioUnitManufacturer_Apple;

    // Get component
    AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc);

    // Get audio units
    status = AudioComponentInstanceNew(inputComponent, &audioUnit);

    UInt32 flag = 1;
    // Enable IO for playback
    status = AudioUnitSetProperty(audioUnit, 
                                  kAudioOutputUnitProperty_EnableIO, 
                                  kAudioUnitScope_Output, 
                                  kOutputBus,
                                  &flag, 
                                  sizeof(flag));

    //Apply format
    status = AudioUnitSetProperty(audioUnit, 
                                  kAudioUnitProperty_StreamFormat, 
                                  kAudioUnitScope_Input, 
                                  kOutputBus, 
                                  &stereoStreamFormat, 
                                  sizeof(stereoStreamFormat));

    // Set up the playback  callback
    AURenderCallbackStruct callbackStruct;
    callbackStruct.inputProc = playbackCallback; //!!****assignment from incompatible pointer warning here *****!!!!!!
    //set the reference to "self" this becomes *inRefCon in the playback callback
    callbackStruct.inputProcRefCon = self;

    status = AudioUnitSetProperty(audioUnit, 
                                  kAudioUnitProperty_SetRenderCallback, 
                                  kAudioUnitScope_Global, 
                                  kOutputBus,
                                  &callbackStruct, 
                                  sizeof(callbackStruct));

    // Initialise
    status = AudioUnitInitialize(audioUnit); // error check this status


}

CallBack

static OSStatus playbackCallback (

                                     void                        *inRefCon,      // A pointer to a struct containing the complete audio data 
                                     //    to play, as well as state information such as the  
                                     //    first sample to play on this invocation of the callback.
                                     AudioUnitRenderActionFlags  *ioActionFlags, // Unused here. When generating audio, use ioActionFlags to indicate silence 
                                     //    between sounds; for silence, also memset the ioData buffers to 0.
                                      AudioTimeStamp        *inTimeStamp,   // Unused here.
                                     UInt32                      inBusNumber,    // The mixer unit input bus that is requesting some new
                                     //        frames of audio data to play.
                                     UInt32                      inNumberFrames, // The number of frames of audio to provide to the buffer(s)
                                     //        pointed to by the ioData parameter.
                                     AudioBufferList             *ioData         // On output, the audio data to play. The callback's primary 
                                     //        responsibility is to fill the buffer(s) in the 
                                     //        AudioBufferList.
                                     ) {


    Engine *remoteIOplayer = (Engine *)inRefCon;
    AudioUnitSampleType *outSamplesChannelLeft;
    AudioUnitSampleType *outSamplesChannelRight;

    outSamplesChannelLeft                 = (AudioUnitSampleType *) ioData->mBuffers[0].mData;
     outSamplesChannelRight  = (AudioUnitSampleType *) ioData->mBuffers[1].mData;

    int thetime =0;
    thetime=remoteIOplayer.sampletime;


        for (int frameNumber = 0; frameNumber < inNumberFrames; ++frameNumber)
        {
            // get NextPacket returns a 32 bit value, one frame.
            AudioUnitSampleType *suml=0;
            AudioUnitSampleType *sumr=0;

            //NSLog (@"frame number -  %i", frameNumber);
            for(int j=0;j<10;j++)

            {


                AudioUnitSampleType valuetoaddl=0;
                AudioUnitSampleType valuetoaddr=0;


                //valuetoadd = [remoteIOplayer getSample:j ];
                valuetoaddl = [remoteIOplayer getNonInterleavedSample:j currenttime:thetime channel:0 ];
                //valuetoaddl = [remoteIOplayer getSample:j];
                valuetoaddr = [remoteIOplayer getNonInterleavedSample:j currenttime:thetime channel:1 ];

                suml = suml+(valuetoaddl/10);
                sumr = sumr+(valuetoaddr/10);

            }


            outSamplesChannelLeft[frameNumber]=(AudioUnitSampleType) suml;
            outSamplesChannelRight[frameNumber]=(AudioUnitSampleType) sumr;


            remoteIOplayer.sampletime +=1;


        }

    return noErr;
}

我的音频提取功能

-(AudioUnitSampleType) getNonInterleavedSample:(int) index currenttime:(int)time channel:(int)ch;

{

    AudioUnitSampleType returnvalue= 0;

    soundStruct snd=soundStructArray[index];    
    UInt64 sn= snd.frameCount;  
    UInt64 st=sampletime;
    UInt64 read= (UInt64)(st%sn);


    if(ch==0)
    {
        if (snd.sendvalue==1) {
            returnvalue = snd.audioDataLeft[read];

        }else {
            returnvalue=0;
        }

    }else if(ch==1)

    {
        if (snd.sendvalue==1) {
        returnvalue = snd.audioDataRight[read];
        }else {
            returnvalue=0;
        }

        soundStructArray[index].sampleNumber=read;
    }


    if(soundStructArray[index].sampleNumber >soundStructArray[index].frameCount)
    {
        soundStructArray[index].sampleNumber=0;

    }

    return returnvalue;


}

编辑1

为了回应@andre,我将回调更改为以下内容,但仍然没有帮助。

static OSStatus playbackCallback (

                                     void                        *inRefCon,      // A pointer to a struct containing the complete audio data 
                                     //    to play, as well as state information such as the  
                                     //    first sample to play on this invocation of the callback.
                                     AudioUnitRenderActionFlags  *ioActionFlags, // Unused here. When generating audio, use ioActionFlags to indicate silence 
                                     //    between sounds; for silence, also memset the ioData buffers to 0.
                                      AudioTimeStamp        *inTimeStamp,   // Unused here.
                                     UInt32                      inBusNumber,    // The mixer unit input bus that is requesting some new
                                     //        frames of audio data to play.
                                     UInt32                      inNumberFrames, // The number of frames of audio to provide to the buffer(s)
                                     //        pointed to by the ioData parameter.
                                     AudioBufferList             *ioData         // On output, the audio data to play. The callback's primary 
                                     //        responsibility is to fill the buffer(s) in the 
                                     //        AudioBufferList.
                                     ) {


    Engine *remoteIOplayer = (Engine *)inRefCon;
    AudioUnitSampleType *outSamplesChannelLeft;
    AudioUnitSampleType *outSamplesChannelRight;

    outSamplesChannelLeft                 = (AudioUnitSampleType *) ioData->mBuffers[0].mData;
     outSamplesChannelRight  = (AudioUnitSampleType *) ioData->mBuffers[1].mData;

    int thetime =0;
    thetime=remoteIOplayer.sampletime;


        for (int frameNumber = 0; frameNumber < inNumberFrames; ++frameNumber)
        {
            // get NextPacket returns a 32 bit value, one frame.
            AudioUnitSampleType suml=0;
            AudioUnitSampleType sumr=0;

            //NSLog (@"frame number -  %i", frameNumber);
            for(int j=0;j<16;j++)

            {



                soundStruct snd=remoteIOplayer->soundStructArray[j];
                UInt64 sn= snd.frameCount;  
                UInt64 st=remoteIOplayer.sampletime;
                UInt64 read= (UInt64)(st%sn);

                suml+=  snd.audioDataLeft[read];
                suml+= snd.audioDataRight[read];


            }


            outSamplesChannelLeft[frameNumber]=(AudioUnitSampleType) suml;
            outSamplesChannelRight[frameNumber]=(AudioUnitSampleType) sumr;


            remoteIOplayer.sampletime +=1;


        }

    return noErr;
}

3 个答案:

答案 0 :(得分:3)

  1. 就像Andre说的那样,最好不要在回调中进行任何Objective-C函数调用。您还应该将inputProcRefCon更改为C-Struct而不是Objective-C对象。

  2. 此外,您可能会逐帧“手动”将数据复制到缓冲区中。相反,使用memcopy复制一大块数据。

  3. 另外,我很确定你在回调中没有进行磁盘I / O,但如果你是,你也不应该这样做。

答案 1 :(得分:2)

根据我的经验,尽量不要在RemoteIO Callback中使用Objective-C函数调用。他们会放慢速度。尝试使用C结构在Callback中移动“getNonInterleavedSample”函数以访问音频数据。

答案 2 :(得分:1)

我认为你是CPU限制的;模拟器在处理速度方面比各种设备更强大。

回调可能无法跟上它被调用的频率。

编辑:你能“预先计算”混音(提前完成或在另一个线程中),以便在回调触发时它已经被混合,并且回调的工作量较少吗?