2

マイクからオーディオをキャプチャし、ハイパス フィルターでフィルター処理して、スピーカーから再生する iOS アプリを作成しています。

AudioUnitRenderiPhone 4S でレンダリング コールバック関数を呼び出すと、-50 OSStatus エラーが発生しますが、シミュレーターでは問題なく動作します。

HPF と出力間の ASBD を一致させるために、ユニット、エフェクト ユニット、およびユニットをAUGraph備えたを使用しています。コンバーターのインスタンスは と呼ばれます。RemoteIOHighPassFilterAUConverterAudioUnitconverterUnit

これがコードです。

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

    AudioController *THIS = (AudioController*)inRefCon;

    AudioBuffer buffer;

    AudioStreamBasicDescription converterOutputASBD;
    UInt32 converterOutputASBDSize = sizeof(converterOutputASBD);
    AudioUnitGetProperty([THIS converterUnit], kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &converterOutputASBD, &converterOutputASBDSize);

    buffer.mDataByteSize = inNumberFrames * converterOutputASBD.mBytesPerFrame;
    buffer.mNumberChannels = converterOutputASBD.mChannelsPerFrame;
    buffer.mData = malloc(buffer.mDataByteSize);

    AudioBufferList bufferList;
    bufferList.mNumberBuffers = 1;
    bufferList.mBuffers[0] = buffer;

    OSStatus result = AudioUnitRender([THIS converterUnit], ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList);

    ...

}

-50 エラーは、パラメーターの 1 つが間違っていることを意味すると思います。残りのすべてが引数として渡されることを考える[THIS converterUnit]と、間違っている可能性がある唯一のパラメーターはと です。&bufferListconverterUnit インスタンスを確認しましたが、正しく割り当てられて初期化されています (さらに、それが問題である場合は、シミュレーターでも実行されません)。チェックするパラメータはbufferList. これまでのデバッグでわかったのは、RemoteIO の出力要素の入力 ASBD とinNumberFrames、電話とシミュレータの両方が異なるということです。AudioBuffer bufferそれでも、呼び出しの結果として生じる ASBD に基づいてメモリを作成して割り当てることを考えると、それは私にとって物事を変えるものではないと思いますAudioUnitGetProperty([THIS ioUnit], kAudioUnitProperty_StreamFormat, ...)

どんな助けでも大歓迎です、私はここで必死に走っています..

あなたたち最高。

乾杯。

アップデート:

オーディオ コントローラー クラスの定義は次のとおりです。

@interface AudioController : NSObject
{
    AUGraph mGraph;
    AudioUnit mEffects;
    AudioUnit ioUnit;
    AudioUnit converterUnit;
}

@property (readonly, nonatomic) AudioUnit mEffects;
@property (readonly, nonatomic) AudioUnit ioUnit;
@property (readonly, nonatomic) AudioUnit converterUnit;

@property (nonatomic) float* volumenPromedio;

-(void)initializeAUGraph;
-(void)startAUGraph;
-(void)stopAUGraph;

@end

、および AUGraph の初期化コード ( で定義AudioController.mm) は次のとおりです。

- (void)initializeAUGraph
{
    NSError *audioSessionError = nil;
    AVAudioSession *mySession = [AVAudioSession sharedInstance];
    [mySession setPreferredHardwareSampleRate: kGraphSampleRate
                                        error: &audioSessionError];
    [mySession setCategory: AVAudioSessionCategoryPlayAndRecord
                     error: &audioSessionError];
    [mySession setActive: YES error: &audioSessionError];

    OSStatus result = noErr;

    // create a new AUGraph
    result = NewAUGraph(&mGraph);

    AUNode outputNode;
    AUNode effectsNode;
    AUNode converterNode;

    // effects component
    AudioComponentDescription effects_desc;
    effects_desc.componentType = kAudioUnitType_Effect;
    effects_desc.componentSubType = kAudioUnitSubType_HighPassFilter;
    effects_desc.componentFlags = 0;
    effects_desc.componentFlagsMask = 0;
    effects_desc.componentManufacturer = kAudioUnitManufacturer_Apple;

    //  output component
    AudioComponentDescription output_desc;
    output_desc.componentType = kAudioUnitType_Output;
    output_desc.componentSubType = kAudioUnitSubType_RemoteIO;
    output_desc.componentFlags = 0;
    output_desc.componentFlagsMask = 0;
    output_desc.componentManufacturer = kAudioUnitManufacturer_Apple;

    // stream format converter component
    AudioComponentDescription converter_desc;
    converter_desc.componentType = kAudioUnitType_FormatConverter;
    converter_desc.componentSubType = kAudioUnitSubType_AUConverter;
    converter_desc.componentFlags = 0;
    converter_desc.componentFlagsMask = 0;
    converter_desc.componentManufacturer = kAudioUnitManufacturer_Apple;

    // Add nodes to the graph
    result = AUGraphAddNode(mGraph, &output_desc, &outputNode);
    [self hasError:result:__FILE__:__LINE__];
    result = AUGraphAddNode(mGraph, &effects_desc, &effectsNode);
    [self hasError:result:__FILE__:__LINE__];
    result = AUGraphAddNode(mGraph, &converter_desc, &converterNode);

    // manage connections in the graph    

    // Connect the io unit node's input element's output to the effectsNode input
    result = AUGraphConnectNodeInput(mGraph, outputNode, 1, effectsNode, 0);

    // Connect the effects node's output to the converter node's input
    result = AUGraphConnectNodeInput(mGraph, effectsNode, 0, converterNode, 0);

    // open the graph
    result = AUGraphOpen(mGraph);

    // Get references to the audio units
    result = AUGraphNodeInfo(mGraph, effectsNode, NULL, &mEffects);
    result = AUGraphNodeInfo(mGraph, outputNode, NULL, &ioUnit);
    result = AUGraphNodeInfo(mGraph, converterNode, NULL, &converterUnit);

    // Enable input on remote io unit
    UInt32 flag = 1;
    result = AudioUnitSetProperty(ioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &flag, sizeof(flag));

    // Setup render callback struct
    AURenderCallbackStruct renderCallbackStruct;
    renderCallbackStruct.inputProc = &renderInput;
    renderCallbackStruct.inputProcRefCon = self;

    result = AUGraphSetNodeInputCallback(mGraph, outputNode, 0, &renderCallbackStruct);

    // Get fx unit's input current stream format...
    AudioStreamBasicDescription fxInputASBD;
    UInt32 sizeOfASBD = sizeof(AudioStreamBasicDescription);

    result = AudioUnitGetProperty(mEffects, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &fxInputASBD, &sizeOfASBD);

    // ...and set it on the io unit's input scope's output 
    result = AudioUnitSetProperty(ioUnit,
                                  kAudioUnitProperty_StreamFormat,
                                  kAudioUnitScope_Output,
                                  1,
                                  &fxInputASBD,
                                  sizeof(fxInputASBD));

    // Set fx unit's output sample rate, just in case
    Float64 sampleRate = 44100.0;

    result = AudioUnitSetProperty(mEffects,
                                  kAudioUnitProperty_SampleRate,
                                  kAudioUnitScope_Output,
                                  0,
                                  &sampleRate,
                                  sizeof(sampleRate));

    AudioStreamBasicDescription fxOutputASBD;

    // get fx audio unit's output ASBD...
    result = AudioUnitGetProperty(mEffects, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &fxOutputASBD, &sizeOfASBD);

    // ...and set it to the converter audio unit's input
    result = AudioUnitSetProperty(converterUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &fxOutputASBD, sizeof(fxOutputASBD));

    AudioStreamBasicDescription ioUnitsOutputElementInputASBD;

    // now get io audio unit's output element's input ASBD...
    result = AudioUnitGetProperty(ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &ioUnitsOutputElementInputASBD, &sizeOfASBD);

    // ...set the sample rate...
    ioUnitsOutputElementInputASBD.mSampleRate = 44100.0;

    // ...and set it to the converter audio unit's output
    result = AudioUnitSetProperty(converterUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &ioUnitsOutputElementInputASBD, sizeof(ioUnitsOutputElementInputASBD));

    // initialize graph
    result = AUGraphInitialize(mGraph);

}

コンバーターの出力とリモート io ユニットの出力要素の入力を (メソッドではなくAUGraphConnectNodeInput) レンダー コールバック関数を使用して接続する理由は、サンプルがサンプルによって処理された直後に計算を行う必要があるためです。ハイパスフィルタ。render コールバックは、呼び出しの直後にサンプル バッファを調べて、AudioUnitRenderそこで計算を行う機会を与えてくれます。

更新 2:

デバッグにより、リモート IO 出力バスの入力 ASBD がデバイスとシミュレータで異なることがわかりました。違いはありません (以前の呼び出しからのデータに基づいて AudioBufferList を割り当てて初期化しAudioUnitGetProperty([THIS ioUnit], kAudioUnitProperty_StreamFormat, ...)ます) が、デバイスとシミュレーターで違いが見られるのはそれだけです。

デバイス上のリモート IO 出力バスの入力 ASBD は次のとおりです。

Float64 mSampleRate        44100
UInt32  mFormatID          1819304813
UInt32  mFormatFlags       41
UInt32  mBytesPerPacket    4
UInt32  mFramesPerPacket   1
UInt32  mBytesPerFrame     4
UInt32  mChannelsPerFrame  2
UInt32  mBitsPerChannel    32
UInt32  mReserved          0

、そしてここにシミュレーターがあります:

Float64 mSampleRate        44100
UInt32  mFormatID          1819304813
UInt32  mFormatFlags       12
UInt32  mBytesPerPacket    4
UInt32  mFramesPerPacket   1
UInt32  mBytesPerFrame     4
UInt32  mChannelsPerFrame  2
UInt32  mBitsPerChannel    16
UInt32  mReserved          0
4

0 に答える 0