2014-06-30 2 views
0

내 애플 오디오 재생 및 녹음 기능, 그리고 사용자가 녹음을 시작할 때 표준 오디오 재생이 음소거 스위치 뮤트 할 수 있도록 만 PlayAndRecord에 오디오 세션의 범주를 설정하려는 등AudioSession 범주를 SoloAmbient에서 PlayAndRecord로 변경 한 후 RemoteIOUnit에서 녹화 할 수없는 이유는 무엇입니까?

I 모두가 그래도 문제가 있는데, 오디오 세션을 PlayAndRecord으로 변경하면 AudioUnitRender에 오디오 입력을 녹음하라는 전화가 errParam (-50)으로 실패합니다. PlayAndRecord 카테고리를 사용하여 앱을 시작하면 올바르게 레코딩됩니다.

@implementation MyAudioSession 
- (instancetype)init { 
    NSError *error = nil; 
    AVAudioSession *session = [AVAudioSession sharedInstance]; 
    [session setCategory:AVAudioSessionCategorySoloAmbient]; 
    [session setActive:YES error:&error]; 
} 

- (void)enableRecording { 
    void (^setCategory)(void) = ^{ 
    NSError *error; 
    AVAudioSession *session = [AVAudioSession sharedInstance]; 
    [session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error]; 
    }; 
    // Do I need to set the category from the main thread? 
    if ([NSThread isMainThread]) { 
    setCategory(); 
    } else { 
    dispatch_sync(dispatch_get_main_queue(), ^{ 
     setCategory(); 
    }); 
    } 
} 
@end 

@interface MyRecorder { 
    AudioUnit ioUnit_; 
    AudioBufferList *tmpRecordListPtr_ 
@end 

@implementation MyRecorder 
- (instancetype)init { 
    // Sets up AUGraph with just a RemoteIOUnit node, recording enabled, callback, etc. 
    // Set up audio buffers 
    tmpRecordListPtr_ = malloc(sizeof(AudioBufferList) + 64 * sizeof(AudioBuffer)); 
} 

- (OSStatus)doRecordCallback:(AudioUnitRenderActionFlags *)ioActionFlags 
        timeStamp:(AudioTimeStamp *)inTimeStamp 
        busNumber:(UInt32)busNumber 
        numFrames:(UInt32)numFrames 
        bufferOut:(AudioBufferList *)ioData { 
    // Set up buffers... All this works fine if I initialize the audio session to 
    // PlayAndRecord in -[MyAudioSession init] 
    OSStatus status = AudioUnitRender(ioUnit_, ioActionFlags, inTimeStamp, busNumber, 
            numFrames, tmpRecordListPtr_); 
    // This fails with errParam, but only if I start my app in SoloAmbient and then 
    // later change it to PlayAndRecord 
} 
@end 

OSStatus MyRecorderCallback(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, 
          AudioTimeStamp *inTimestamp, UInt32 inBusNumber, 
          UInt32 inNumberFrames, AudioBufferList *ioData) { 
    MyRecorder *recorder = (MyRecorder *)inRefCon; 
    return [recorder doRecordCallback:ioActionFlags 
          timeStamp:inTimestamp 
          busNumber:inBusNumber 
          numFrames:inNumberFrames 
          bufferOut:ioData]; 
} 

iOS 7.1.2를 실행하는 iPod touch (5 세대)에서 테스트 중입니다.

다른 사람이이 문제를 겪었습니까? 내가 게시 할 수있는 수정 사항이나 추가 정보에 대한 제안 사항이 있습니까?

편집 : 언급하기 어려운 코드를 보지 않고

- (void)startRecording { 
    [mySession enableRecording]; 
    [myRecorder release]; 
    myRecorder = [[MyRecorder alloc] init]; 
    [myRecorder start]; // starts the AUGraph 
} 

답변

0

: 개체의 라이프 사이클과 유사하다. 하지만 내 응용 프로그램에서 비슷한 일을하고있어, 오디오 세션이 비활성화 된 경우에만 오디오 세션 설정을 변경할 수있는 것에주의를 기울이는 것이 중요하다는 사실을 발견했습니다.

// Get the app's audioSession singleton object 
AVAudioSession* session = [AVAudioSession sharedInstance]; 

//error handling 
NSError* audioSessionError = nil; 

SDR_DEBUGPRINT(("Setting session not active!\n")); 
[session setActive:NO error:&audioSessionError]; // shut down the audio session if it is active 

예를 들어 세션 범주를 변경하기 전에 반드시 "아니오"로 설정하는 것이 중요합니다. 이렇게하지 않으면 세션이 구성되는 동안 렌더링 콜백이 발생할 수 있습니다.

수명주기 흐름을 살펴보면 레코딩을 위해 오디오 세션을 설정하기 전에 AUGraph를 중지하는 위치를 확인하려고합니다. AUGraph를 중지하기 위해 사용하는 코드는 다음과 같습니다. 오디오 세션을 재구성하려고 시도하기 전에 그것을 호출합니다. 비활성화 및/또는 오디오 세션 유형을 변경하기 전에

- (void)stopAUGraph { 
if(mAudioGraph != nil) { 
    Boolean isRunning = FALSE; 

    OSStatus result = AUGraphIsRunning(mAudioGraph, &isRunning); 
    if(result) { 
     DEBUGPRINT(("AUGraphIsRunning result %d %08X %4.4s\n", (int)result, (int)result, (char*)&result)); 
     return; 
    } 

    if(isRunning) { 
     result = AUGraphStop(mAudioGraph); 

     if(result) { 
      DEBUGPRINT(("AUGraphStop result %d %08X %4.4s\n", (int)result, (int)result, (char*)&result)); 
      return; 
     } else { 
      DEBUGPRINT(("mAudioGraph has been stopped!\n")); 
     } 
    } else { 
     DEBUGPRINT(("mAudioGraph is already stopped!\n")); 
    } 
} 
+0

'-setActive :'는 오디오 세션이 활성화되어있는 동안 호출 할 수 있도록 문서화되어 있습니다.하지만 라우트 변경 알림을 발생시킵니다. 어떤 경우이든 카테고리를 변경하기 전에 내 세션을 비활성화해도 도움이되지 않습니다. 관련성이있는 코드를 게시 해 보겠습니다. 나는이 코드베이스에 꽤 익숙하다. 그래서 나는 뭔가를 놓칠지도 모른다. – Greg

+0

오디오 세션을 재구성하는 동안 렌더링 콜백이 발생하지 않도록해야 할 필요가 있다고 생각합니다. 나는 실제로 remoteIO 유닛을 폐기하고 세션이 재구성 될 때마다 새로운 유닛을 생성한다. 그러나 콜백을 비활성화하고 기존 장치 인스턴스를 다시 구성하는 것으로 충분할 수 있습니다. – user2338215

+0

녹음을 위해 세션을 재구성 한 후에 이미 녹음기 그래프를 폐기하고 다시 작성하고 있습니다. 레코더 객체 라이프 사이클이 질문과 어떤 관련이 있는지를 보여주는 의사 코드를 추가했습니다. – Greg

0

당신은 확실히 RemoteIO 오디오 장치 (오디오 그래프가) 중지를 확인해야합니다. 그런 다음 새 세션 유형을 설정하면 일부 설정이 변경 될 수 있으므로 새 세션 유형을 설정하고 그래프를 시작하기 전에 (다시) RemoteIO Audio Unit을 초기화하십시오. 또한 그래프 (재)가 시작되기 전에 이전 오디오 장치 및 오디오 세션 호출 오류 코드를 모두 확인하는 것이 좋습니다.

+0

세션 범주를 변경하면 오디오 그래프가 실행되지 않고 범주를 변경 한 후 그래프를 다시 작성하려고했습니다. 범주를 변경 한 후 기본 샘플 속도와 IO 버퍼 지속 기간을 다시 설정하여 작동 시켰지만 이제는 코드가 엉망입니다. 정확히 무엇이 차이를 만들고 내 코드를 정리했는지 파악한 후에 내가 찾은 것을 게시 할 것입니다. – Greg

+0

RemoteIO 장치가 새로운 오디오 세션 유형 하에서 OS에 연결하는 방법과 일치하도록 RemoteIO 샘플 속도 및 버퍼 지속 시간을 재구성해야 할 수 있습니다. – hotpaw2

+0

내가 찾은 것을 추가로 확인하는 것과 마찬가지로, 앱을 만들 때마다 remoteIO에서 매개 변수를 설정합니다. 오디오 세션 카테고리를 변경해도 문제가 없습니다. – user2338215