-1

VOIPアプリケーションを開発しようとしていますが、

  • RecordingCallBack から取得したオーディオ バッファは NSData にラップされ、GCDAsyncSocket によってリモート側に送信されます。

  • リモート側は
    NSData を取得し、オーディオ バッファーにラップ解除し、PlayingCallBack がオーディオ バッファーをフェッチします。

私の計画はこれまでのところ機能しており、ローカルで正常に実行されています(ソケットはデータをローカルに送信し、バッファをローカルで再生します)

しかし、2 つのデバイス (1 つの本物の iPhone-4s、1 つのシミュレーター) で実行すると、音声が奇妙になり、ロボットの音のように聞こえます。

とにかくロボットの効果音を避ける方法はありますか?

これが私のAudioUnit設定です:

#pragma mark - Init Methods

- (void)initAudioUint
{
    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);
    checkStatus(status);

    // Enable IO for recording
    UInt32 flag = 1;
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioOutputUnitProperty_EnableIO,
                                  kAudioUnitScope_Input,
                                  kInputBus,
                                  &flag,
                                  sizeof(flag));
    checkStatus(status);

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

    // Describe format
    AudioStreamBasicDescription audioFormat;
    audioFormat.mSampleRate = 44100.0f; // FS
    audioFormat.mFormatID = kAudioFormatLinearPCM;
    audioFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
    audioFormat.mChannelsPerFrame = 1; // stereo output
    audioFormat.mFramesPerPacket = 1;
    audioFormat.mBitsPerChannel = sizeof(short) * 8; // 16-bit
    audioFormat.mBytesPerFrame = audioFormat.mBitsPerChannel / 8 * audioFormat.mChannelsPerFrame;
    audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame * audioFormat.mFramesPerPacket;

    // Apply format
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioUnitProperty_StreamFormat,
                                  kAudioUnitScope_Output,
                                  kInputBus,
                                  &audioFormat,
                                  sizeof(audioFormat));
    checkStatus(status);
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioUnitProperty_StreamFormat,
                                  kAudioUnitScope_Input,
                                  kOutputBus,
                                  &audioFormat,
                                  sizeof(audioFormat));
    checkStatus(status);


    // Set input callback
    AURenderCallbackStruct callbackStruct;
    callbackStruct.inputProc = recordingCallback;
    callbackStruct.inputProcRefCon = (__bridge void*)self;
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioOutputUnitProperty_SetInputCallback,
                                  kAudioUnitScope_Global,
                                  kInputBus,
                                  &callbackStruct,
                                  sizeof(callbackStruct));
    checkStatus(status);


    // Set output callback
    callbackStruct.inputProc = playbackCallback;
    callbackStruct.inputProcRefCon = (__bridge void*)self;
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioUnitProperty_SetRenderCallback,
                                  kAudioUnitScope_Global,
                                  kOutputBus,
                                  &callbackStruct,
                                  sizeof(callbackStruct));
    checkStatus(status);


    /*
    // Disable buffer allocation for the recorder (optional - do this if we want to pass in our own)
    flag = 0;
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioUnitProperty_ShouldAllocateBuffer,
                                  kAudioUnitScope_Output,
                                  kInputBus,
                                  &flag,
                                  sizeof(flag));

    // Allocate our own buffers (1 channel, 16 bits per sample, thus 16 bits per frame, thus 2 bytes per frame).
    // Practice learns the buffers used contain 512 frames, if this changes it will be fixed in processAudio.
    tempBuffer.mNumberChannels = 1;
    tempBuffer.mDataByteSize = 512 * 2;
    tempBuffer.mData = malloc( 512 * 2 );
    checkStatus(status);


    // Disable buffer allocation for the recorder (optional - do this if we want to pass in our own)
    flag = 0;
    status = AudioUnitSetProperty(audioUnit,
                                  kAudioUnitProperty_ShouldAllocateBuffer,
                                  kAudioUnitScope_Output,
                                  kInputBus,
                                  &flag,
                                  sizeof(flag));

    // TODO: Allocate our own buffers if we want
    */

    // Initialise
    status = AudioUnitInitialize(audioUnit);
    checkStatus(status);

    conversionBuffer = (SInt16 *) malloc(1024 * sizeof(SInt16));
}

ところで、 audioFormat.mFramesPerPacket > 1 を設定する方法はありますか?

私の場合、param > 1の場合、エラーが出力されます。

マルチフレームを含むバッファを送信することを考えていました(リモート側で再生するためにより多くの時間を取得するため)、VOIP用に1フレーム1パケットを送信するよりも優れているはずですか?

4

2 に答える 2

0

2つのデバイスのオーディオサンプルレートクロックは完全に同期されないため、わずかなサンプルレートの不一致、およびネットワークレイテンシジッターによるバッファアンダーフローとオーバーフローを処理する必要があります。

また、RemoteIOコールバックに送信されるバッファーサイズは一定に保たれない可能性があるため、2つのコールバックがバッファーサイズの不一致を処理できる必要があることにも注意してください。

于 2012-11-23T07:49:32.230 に答える
0

私は今この問題を解決しました!

オーディオ セッションのプロパティを設定する必要があります。2 つのデバイスの BufferDuration が同じであることを確認してください。

    // set preferred buffer size
    Float32 audioBufferSize = (set up the duration);
    UInt32 size = sizeof(audioBufferSize);
    result = AudioSessionSetProperty(kAudioSessionProperty_PreferredHardwareIOBufferDuration,
                           size, &audioBufferSize);
于 2012-11-26T16:24:37.847 に答える