RemoteIO Audio Проблема - симулятор = хорошо - устройство = плохо - PullRequest
2 голосов
/ 01 декабря 2010

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

В симуляторе все работает отлично, и все было хорошо.Однако я столкнулся с проблемой, когда попытался запустить его на устройстве iPhone 4,2.

Если я смешаю 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 ]

3 голосов
/ 01 декабря 2010
  1. Как сказал Андре, лучше не иметь вызовов функции Objective C в обратном вызове.Вам также следует изменить свой inputProcRefCon на C-Struct вместо объекта Objective-C.

  2. Кроме того, похоже, что вы можете выполнять покадровое «ручное» копированиеданные в буфер.Вместо этого используйте memcopy, чтобы скопировать порцию данных.

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

2 голосов
/ 01 декабря 2010

По моему опыту, старайтесь не использовать вызовы функций Objective C в вашем обратном вызове RemoteIO. Они замедлят это. Попробуйте переместить свою функцию «getNonInterleavedSample» в Обратный вызов, используя структуры C для доступа к аудиоданным.

1 голос
/ 01 декабря 2010

Я полагаю, вы ограничены в процессоре;Симулятор гораздо более мощный с точки зрения скорости обработки, чем различные устройства.

Обратный вызов, вероятно, не справляется с частотой, с которой он вызывается.

РЕДАКТИРОВАТЬ: Не могли бы вы "Предварительно вычислите «микширование (делая это заранее или в другом потоке), чтобы оно уже было смешанным, когда сработал обратный вызов, и у обратного вызова было меньше работы?

...