2016-10-27 8 views
3

내 VOIP 앱의 기초로 SpeakerBox 앱을 사용하고 있습니다. 나는 모든 것을 작동시킬 수 있었지만, 마이크에서 장치의 스피커까지 오디오의 "단락"을 제거하는 것처럼 보이지는 않습니다.CallKit이 포함 된 VOIP 앱의 오디오 단락

즉, 전화를 걸면 다른 사람의 음성은 물론 스피커에서 나 자신을들을 수 있습니다. 이걸 어떻게 바꿀 수 있니?

AVAudioSession 설정 : IO 단위의

AVAudioSession *sessionInstance = [AVAudioSession sharedInstance]; 

    NSError *error = nil; 
    [sessionInstance setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]; 
    XThrowIfError((OSStatus)error.code, "couldn't set session's audio category"); 

    [sessionInstance setMode:AVAudioSessionModeVoiceChat error:&error]; 
    XThrowIfError((OSStatus)error.code, "couldn't set session's audio mode"); 

    NSTimeInterval bufferDuration = .005; 
    [sessionInstance setPreferredIOBufferDuration:bufferDuration error:&error]; 
    XThrowIfError((OSStatus)error.code, "couldn't set session's I/O buffer duration"); 

    [sessionInstance setPreferredSampleRate:44100 error:&error]; 
    XThrowIfError((OSStatus)error.code, "couldn't set session's preferred sample rate"); 

설정 :

- (void)setupIOUnit 
{ 
try { 
    // Create a new instance of Apple Voice Processing IO 

    AudioComponentDescription desc; 
    desc.componentType = kAudioUnitType_Output; 
    desc.componentSubType = kAudioUnitSubType_VoiceProcessingIO; 
    desc.componentManufacturer = kAudioUnitManufacturer_Apple; 
    desc.componentFlags = 0; 
    desc.componentFlagsMask = 0; 

    AudioComponent comp = AudioComponentFindNext(NULL, &desc); 
    XThrowIfError(AudioComponentInstanceNew(comp, &_rioUnit), "couldn't create a new instance of Apple Voice Processing IO"); 

    // Enable input and output on Apple Voice Processing IO 
    // Input is enabled on the input scope of the input element 
    // Output is enabled on the output scope of the output element 

    UInt32 one = 1; 
    XThrowIfError(AudioUnitSetProperty(_rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &one, sizeof(one)), "could not enable input on Apple Voice Processing IO"); 
    XThrowIfError(AudioUnitSetProperty(_rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &one, sizeof(one)), "could not enable output on Apple Voice Processing IO"); 

    // Explicitly set the input and output client formats 
    // sample rate = 44100, num channels = 1, format = 32 bit floating point 

    CAStreamBasicDescription ioFormat = CAStreamBasicDescription(44100, 1, CAStreamBasicDescription::kPCMFormatFloat32, false); 
    XThrowIfError(AudioUnitSetProperty(_rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 1, &ioFormat, sizeof(ioFormat)), "couldn't set the input client format on Apple Voice Processing IO"); 
    XThrowIfError(AudioUnitSetProperty(_rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &ioFormat, sizeof(ioFormat)), "couldn't set the output client format on Apple Voice Processing IO"); 

    // Set the MaximumFramesPerSlice property. This property is used to describe to an audio unit the maximum number 
    // of samples it will be asked to produce on any single given call to AudioUnitRender 
    UInt32 maxFramesPerSlice = 4096; 
    XThrowIfError(AudioUnitSetProperty(_rioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFramesPerSlice, sizeof(UInt32)), "couldn't set max frames per slice on Apple Voice Processing IO"); 

    // Get the property value back from Apple Voice Processing IO. We are going to use this value to allocate buffers accordingly 
    UInt32 propSize = sizeof(UInt32); 
    XThrowIfError(AudioUnitGetProperty(_rioUnit, kAudioUnitProperty_MaximumFramesPerSlice, kAudioUnitScope_Global, 0, &maxFramesPerSlice, &propSize), "couldn't get max frames per slice on Apple Voice Processing IO"); 

    // We need references to certain data in the render callback 
    // This simple struct is used to hold that information 

    cd.rioUnit = _rioUnit; 
    cd.muteAudio = &_muteAudio; 
    cd.audioChainIsBeingReconstructed = &_audioChainIsBeingReconstructed; 

    // Set the render callback on Apple Voice Processing IO 
    AURenderCallbackStruct renderCallback; 
    renderCallback.inputProc = performRender; 
    renderCallback.inputProcRefCon = NULL; 
    XThrowIfError(AudioUnitSetProperty(_rioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, 0, &renderCallback, sizeof(renderCallback)), "couldn't set render callback on Apple Voice Processing IO"); 

    // Initialize the Apple Voice Processing IO instance 
    XThrowIfError(AudioUnitInitialize(_rioUnit), "couldn't initialize Apple Voice Processing IO instance"); 
} 

catch (CAXException &e) { 
    NSLog(@"Error returned from setupIOUnit: %d: %s", (int)e.mError, e.mOperation); 
} 
catch (...) { 
    NSLog(@"Unknown error returned from setupIOUnit"); 
} 

return; 
} 

는 IOUnit를 시작하려면 다음

NSError *error = nil; 
[[AVAudioSession sharedInstance] setActive:YES error:&error]; 
if (nil != error) NSLog(@"AVAudioSession set active (TRUE) failed with error: %@", error); 

OSStatus err = AudioOutputUnitStart(_rioUnit); 
if (err) NSLog(@"couldn't start Apple Voice Processing IO: %d", (int)err); 
return err; 

을 IOUnit

NSError *error = nil; 
[[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error]; 
if (nil != error) NSLog(@"AVAudioSession set active (FALSE) failed with error: %@", error); 

OSStatus err = AudioOutputUnitStop(_rioUnit); 
if (err) NSLog(@"couldn't stop Apple Voice Processing IO: %d", (int)err); 
return err; 
,369를 중지하려면

저는 SIP 스택으로 PJSIP을 사용하고 있으며 별표 (*)가 있습니다. 이 문제는 안드로이드 기반의 PJSIP 구현이 있기 때문에이 문제는 클라이언트 측이어야합니다.

+0

내 앱과 거의 동일한 문제도 조사 중입니다. speakerbox 코드는 스피커 박스의 설정을 올바르게 이해했다면 스피커로 입력을 스트리밍합니다. 그래서 나는 그 예제 코드를 사용하지 않고있다. pjsua_set_no_snd_dev() 및 pjsua_set_snd_dev()를 사용하여 사용하고 있습니다. 제 경우에는 다른 쪽이이 단락 회로 문제로 영향을받습니다. 그런데 CallKit을 사용하지 않으면 내 이식이 잘됩니다. –

+0

좋아, 다른 쪽이 자신의 목소리를들을 수있는 나이가 많은 iOS 버전에도 내 문제가 있습니다.이 문제의 원인 및 원인을 잘 모릅니다. 귀하의 경우, 나는 pjsip 함수를 사용한다고 말할 것이다. pjsip 및 CallKit에 대한 자세한 내용은 https://trac.pjsip.org/repos/ticket/1941을 확인하십시오. –

답변

2

WebRTC를 사용하여 동일한 문제에 대해 설명했습니다. 마침내 필자는 AudioController.mm에서 IOUnit을 설정하지 말고 PJSIP (내 경우에는 WebRTC)로 남겨 두어야한다고 결론을 내 렸습니다. ProviderDelegate.swiftdidActivate audioSession에서 AudioController.mm의 setupAudioChain뿐만 아니라 startAudio()에 을 주석 [self setupIOUnit]; :

빠른 수정 사항은 다음과 같다.