2011-03-31 5 views
3

기기 (iPhone4)의 마이크에서 입력 신호를 캡처 할 수없는 문제가 발생했습니다. 그러나 코드는 시뮬레이터에서 제대로 실행됩니다. 코드는 원래 Apple의 MixerHostAudio 클래스의 MixerHost 샘플 코드에서 채택되었습니다. 그것은 마이크 입력 캡처를위한 코드를 추가하기 전에 장치와 시뮬레이터에서 잘 실행됩니다. 누군가 나를 도울 수 있는지 궁금합니다. 미리 감사드립니다!iOS - AudioUnitRender가 기기에서 -10876 오류를 반환했지만 시뮬레이터에서 정상적으로 실행 중입니다.

다음
static OSStatus inputRenderCallback (

void      *inRefCon, 
AudioUnitRenderActionFlags *ioActionFlags, 
const AudioTimeStamp  *inTimeStamp, 
UInt32      inBusNumber, 
UInt32      inNumberFrames, 
AudioBufferList    *ioData) { 
recorderStructPtr recorderStructPointer  = (recorderStructPtr) inRefCon; 
    // .... 
     AudioUnitRenderActionFlags renderActionFlags; 
     err = AudioUnitRender(recorderStructPointer->iOUnit, 
           &renderActionFlags, 
           inTimeStamp, 
           1, // bus number for input 
           inNumberFrames, 
           recorderStructPointer->fInputAudioBuffer 
          ); 
        // error returned is -10876 
    // .... 
} 

내 관련 초기화 코드입니다 : 가 지금은 믹서 중복 보인다 있도록, 믹서 만 1 개 입력을 유지하지만, 잘 작동 여기

믹서 입력에 신호를 공급 내 inputRenderCallback 기능입니다 인풋 캡쳐 코드를 추가하기 전에.

// Convenience function to allocate our audio buffers 
- (AudioBufferList *) allocateAudioBufferListByNumChannels:(UInt32)numChannels withSize:(UInt32)size { 
    AudioBufferList*   list; 
    UInt32      i; 

    list = (AudioBufferList*)calloc(1, sizeof(AudioBufferList) + numChannels * sizeof(AudioBuffer)); 
    if(list == NULL) 
     return nil; 

    list->mNumberBuffers = numChannels; 
    for(i = 0; i < numChannels; ++i) { 
     list->mBuffers[i].mNumberChannels = 1; 
     list->mBuffers[i].mDataByteSize = size; 
     list->mBuffers[i].mData = malloc(size); 
     if(list->mBuffers[i].mData == NULL) { 
      [self destroyAudioBufferList:list]; 
      return nil; 
     } 
    } 
    return list; 
} 

// initialize audio buffer list for input capture 
recorderStructInstance.fInputAudioBuffer = [self allocateAudioBufferListByNumChannels:1 withSize:4096]; 

// I/O unit description 
AudioComponentDescription iOUnitDescription; 
iOUnitDescription.componentType   = kAudioUnitType_Output; 
iOUnitDescription.componentSubType  = kAudioUnitSubType_RemoteIO; 
iOUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple; 
iOUnitDescription.componentFlags   = 0; 
iOUnitDescription.componentFlagsMask  = 0; 

// Multichannel mixer unit description 
AudioComponentDescription MixerUnitDescription; 
MixerUnitDescription.componentType   = kAudioUnitType_Mixer; 
MixerUnitDescription.componentSubType  = kAudioUnitSubType_MultiChannelMixer; 
MixerUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple; 
MixerUnitDescription.componentFlags   = 0; 
MixerUnitDescription.componentFlagsMask  = 0; 

AUNode iONode;   // node for I/O unit 
AUNode mixerNode;  // node for Multichannel Mixer unit 

// Add the nodes to the audio processing graph 
result = AUGraphAddNode (
       processingGraph, 
       &iOUnitDescription, 
       &iONode); 

result = AUGraphAddNode (
       processingGraph, 
       &MixerUnitDescription, 
       &mixerNode 
      ); 

result = AUGraphOpen (processingGraph); 

// fetch mixer AudioUnit instance 
result = AUGraphNodeInfo (
       processingGraph, 
       mixerNode, 
       NULL, 
       &mixerUnit 
      ); 

// fetch RemoteIO AudioUnit instance 
result = AUGraphNodeInfo (
          processingGraph, 
          iONode, 
          NULL, 
          &(recorderStructInstance.iOUnit) 
          ); 


    // enable input of RemoteIO unit 
UInt32 enableInput = 1; 
AudioUnitElement inputBus = 1; 
result = AudioUnitSetProperty(recorderStructInstance.iOUnit, 
           kAudioOutputUnitProperty_EnableIO, 
           kAudioUnitScope_Input, 
           inputBus, 
           &enableInput, 
           sizeof(enableInput) 
          ); 
// setup mixer inputs 
UInt32 busCount = 1; 

result = AudioUnitSetProperty (
      mixerUnit, 
      kAudioUnitProperty_ElementCount, 
      kAudioUnitScope_Input, 
      0, 
      &busCount, 
      sizeof (busCount) 
     ); 


UInt32 maximumFramesPerSlice = 4096; 

result = AudioUnitSetProperty (
      mixerUnit, 
      kAudioUnitProperty_MaximumFramesPerSlice, 
      kAudioUnitScope_Global, 
      0, 
      &maximumFramesPerSlice, 
      sizeof (maximumFramesPerSlice) 
     ); 


for (UInt16 busNumber = 0; busNumber < busCount; ++busNumber) { 

    // set up input callback 
    AURenderCallbackStruct inputCallbackStruct; 
    inputCallbackStruct.inputProc  = &inputRenderCallback; 
inputCallbackStruct.inputProcRefCon = &recorderStructInstance; 

    result = AUGraphSetNodeInputCallback (
       processingGraph, 
       mixerNode, 
       busNumber, 
       &inputCallbackStruct 
      ); 

      // set up stream format 
    AudioStreamBasicDescription mixerBusStreamFormat; 
    size_t bytesPerSample = sizeof (AudioUnitSampleType); 

    mixerBusStreamFormat.mFormatID   = kAudioFormatLinearPCM; 
    mixerBusStreamFormat.mFormatFlags  = kAudioFormatFlagsAudioUnitCanonical; 
    mixerBusStreamFormat.mBytesPerPacket = bytesPerSample; 
    mixerBusStreamFormat.mFramesPerPacket = 1; 
    mixerBusStreamFormat.mBytesPerFrame  = bytesPerSample; 
    mixerBusStreamFormat.mChannelsPerFrame = 2; 
    mixerBusStreamFormat.mBitsPerChannel = 8 * bytesPerSample; 
    mixerBusStreamFormat.mSampleRate  = graphSampleRate; 

    result = AudioUnitSetProperty (
            mixerUnit, 
            kAudioUnitProperty_StreamFormat, 
            kAudioUnitScope_Input, 
            busNumber, 
            &mixerBusStreamFormat, 
            sizeof (mixerBusStreamFormat) 
            ); 


} 

// set sample rate of mixer output 
result = AudioUnitSetProperty (
      mixerUnit, 
      kAudioUnitProperty_SampleRate, 
      kAudioUnitScope_Output, 
      0, 
      &graphSampleRate, 
      sizeof (graphSampleRate) 
     ); 


// connect mixer output to RemoteIO 
result = AUGraphConnectNodeInput (
      processingGraph, 
      mixerNode,   // source node 
      0,     // source node output bus number 
      iONode,   // destination node 
      0     // desintation node input bus number 
     ); 


// initialize AudioGraph 
result = AUGraphInitialize (processingGraph); 

// start AudioGraph 
result = AUGraphStart (processingGraph); 

// enable mixer input 
result = AudioUnitSetParameter (
        mixerUnit, 
        kMultiChannelMixerParam_Enable, 
        kAudioUnitScope_Input, 
        0, // bus number 
        1, // on 
        0 
       ); 

답변

1

나는 혼자서이 문제를 해결했다. 내 코드의 버그로 인해 AudioUnitRender()에 10876 오류가 발생했습니다.

나는 로 AVAudioSessionCategoryPlayback 대신 의 AVAudioSessionCategoryPlayAndRecord을 내 AudioSession의 범주를 설정합니다. 카테고리를 AVAudioSessionCategoryPlayAndRecord으로 고정하면 기기에서 A * udioUnitRender() *을 호출하여 마침내 마이크 입력을 성공적으로 캡처 할 수 있습니다.

AVAudioSessionCategoryPlayback을 사용하면 AudioUnitRender()을 호출 할 때 오류가 발생하지 않으며 마이크 입력을 캡처 할 수 있으며 시뮬레이터에서 제대로 작동합니다. 이 문제는 iOS 시뮬레이터 (중요하지 않음)의 문제 여야한다고 생각합니다.

1

먼저, 에러 코드가 -10876 kAudioUnitErr_NoConnection라는 기호에 해당 주목해야한다. 일반적으로 CoreAudio라는 용어와 함께 오류 코드 번호를 찾아서 찾을 수 있습니다. 시스템이 제대로 연결되지 않은 AudioUnit을 렌더링하도록 요청하는 힌트 여야합니다.

렌더 콜백 내에서 void* 사용자 데이터를 recorderStructPtr으로 전송 중입니다. 이 코드를 디버깅 할 때이 캐스트가 실제 오디오 장치의 주소가있는 null이 아닌 구조를 반환했다고 가정합니다. 그러나 렌더 콜백에 전달 된 AudioBufferList (즉, inputRenderCallback 함수)으로 렌더링해야합니다. 여기에는 처리해야하는 시스템의 샘플 목록이 들어 있습니다.

+0

안녕하세요, 귀하의 도움말 주셔서 감사합니다. AudioUnitRender()는 AudioUnitRender()에 전달 된 ABL이 콜백에 전달 된 ABL 일 필요가 없어야하므로 하드웨어에서 샘플을 가져옵니다. 어쨌든했는데 -10876 오류가보고되었습니다.이 NoConnection 오류에 관해서는 이미 Google에이 오류를 설명하는 메일/게시물이 2 개 밖에 없습니다. (내 게시물은 여기에 검색 결과를 두 번). 시뮬레이터와 장치에서 다르게 동작하는 것은 이미 이상한 행동이라고 생각합니다. –

+0

btw 디버거를 사용하여 포인터 주소를 확인한 이후로 recorderStructPtr이 올바르다 고 생각합니다. –

0

또한이 문제는 I/O 장치의 스트림 형식 속성 값이 일치하지 않을 때 발생합니다. 채널당 채널 수, 채널 당 채널 수, 프레임 당 바이트 수, 패킷 당 프레임 수 및 패킷 당 바이트 수는 모두 AudioStreamBasicDescription이어야합니다.

특히 프레임 당 채널을 변경하여 스트림 형식을 스테레오에서 모노로 변경했을 때 NoConnection 오류가 발생했지만 프레임 당 바이트 수와 패킷 당 바이트 수를 변경하는 것을 잊어 버렸습니다. 모노 프레임에서 스테레오 프레임으로.

관련 문제